S
SolidJS•3w ago
hrtwrm

data is rendering correctly on file save but not on page refresh

I am unsure exactly what is happening but when I refresh the page using create resource no data loads. However if I save the file in my editor suddenly the data pops up. I am assuming this is an issue with SSR somehow, but I do not understand what I am doing wrong.
import { createEffect, createResource, Show } from "solid-js";
import { createExternalApi } from "~/server/externalApi";

const resource = async () => {
const externalApi = await createExternalApi();
const userInfo = await externalApi.getUserInfo();
const userInfoResponse = await userInfo.response?.json();

return userInfoResponse;
}

export const UserDetails = () => {
const [data] = createResource(resource);

return (
<>
<Show when={data.loading}>Loading</Show>
<Show when={data.error}>Error</Show>
<Show when={data()}>{(data) => data().username}</Show> // only renders on file save
</>
);
}
import { createEffect, createResource, Show } from "solid-js";
import { createExternalApi } from "~/server/externalApi";

const resource = async () => {
const externalApi = await createExternalApi();
const userInfo = await externalApi.getUserInfo();
const userInfoResponse = await userInfo.response?.json();

return userInfoResponse;
}

export const UserDetails = () => {
const [data] = createResource(resource);

return (
<>
<Show when={data.loading}>Loading</Show>
<Show when={data.error}>Error</Show>
<Show when={data()}>{(data) => data().username}</Show> // only renders on file save
</>
);
}
Any thoughts here would be greatly appreciated. I have been banging my head against the wall on this one.
110 Replies
REEEEE
REEEEE•3w ago
Wrap the data().username in a fragment or any html element
hrtwrm
hrtwrmOP•2w ago
Unfortunately even doing something like <div>{data().username}</div> is not working Anyone else have any ideas?
Madaxen86
Madaxen86•2w ago
Can you share the "server/externalAPI" file?
hrtwrm
hrtwrmOP•2w ago
@Madaxen86 It's just returning an API. What I've found debugging through this is that when the component loads the first time it's not even calling the async function. When I save the file it does run the async function and everything works correctly. Is it possibly an issue with it being in the server directory and running on the server?\
REEEEE
REEEEE•2w ago
How are you rendering the component?
hrtwrm
hrtwrmOP•2w ago
Yeah, so data is just undefined when I refresh the page When I save, suddenly it's available The code above is what I have
REEEEE
REEEEE•2w ago
That's all the code?
hrtwrm
hrtwrmOP•2w ago
Yes
REEEEE
REEEEE•2w ago
How does UserDetails get rendered
hrtwrm
hrtwrmOP•2w ago
What's weird is when I use a regular fetch in there it works perfect So it might be the way this external API is working I am just perplexed why the API wouldn't work on a refresh but then on a save
REEEEE
REEEEE•2w ago
I think the component isn't getting rendered properly so the hmr "fixes" it when you save
hrtwrm
hrtwrmOP•2w ago
What would cause it not to be rendered properly?
REEEEE
REEEEE•2w ago
Props destructuring possibly some invisible error
hrtwrm
hrtwrmOP•2w ago
Yeah the weird thing is there is no error
REEEEE
REEEEE•2w ago
Are you able to reproduce the issue either in the playground or in a fresh project?
hrtwrm
hrtwrmOP•2w ago
I don't think so, I think this is specific to me Because it works otherwise with fetch
REEEEE
REEEEE•2w ago
Hm, does createExternalApi use use server ?
hrtwrm
hrtwrmOP•2w ago
No I did try it and it didn't make a difference So, data is undefined and never gets reevaluated on page refresh On save it does
REEEEE
REEEEE•2w ago
What if you wrap the resource with another function like
const [data] = createResource(async () => await resource());
const [data] = createResource(async () => await resource());
hrtwrm
hrtwrmOP•2w ago
And I see it in the console, it logs data multiple times Let me see Crashed the development server lol
REEEEE
REEEEE•2w ago
Progress lol Wonder why
hrtwrm
hrtwrmOP•2w ago
I dunno
REEEEE
REEEEE•2w ago
Any errors?
hrtwrm
hrtwrmOP•2w ago
Like I said when I log data() on page refresh... it doesn't reevaluate or anything. When I save, it reevaluates a couple of times until it finally gets something other than undefined. data is initially undefined until the server is done fetching. No errors
REEEEE
REEEEE•2w ago
Yeah I get that, but you said the dev server crashed so I was wondering if there were any errors
hrtwrm
hrtwrmOP•2w ago
I had to change it to (() => resource()); because async and await did nothing in that context Oh wait I missed something Okay so actually tried what you suggested and same result -- I forgot to call the method Refresh no data, save has data
REEEEE
REEEEE•2w ago
Did you try logging in an effect yet?
hrtwrm
hrtwrmOP•2w ago
No, let me try Yeah same thing. On a save it evaluates twice. On a refresh only once. So I get undefined on a refresh... then I get undefined and then data on a save. In the console So weird Maybe the JSON is malformed?
REEEEE
REEEEE•2w ago
🤷‍♂️ Is the resource function called? Like if you put a log in it, is it called?
hrtwrm
hrtwrmOP•2w ago
No on a page refresh. If I look in the network tab it's not making an API call. When I save it does. I am assuming there is some error happening that's halting it And I can't see it
REEEEE
REEEEE•2w ago
Yeah so try putting some logs in the function and output each value for externalApi, userInfo, and userInfoResponse and see what you get
hrtwrm
hrtwrmOP•2w ago
On refresh nothing logs -- on file save it all logs lol wth It's not even running the function on a refresh
REEEEE
REEEEE•2w ago
so maybe the component isn't being rendered
hrtwrm
hrtwrmOP•2w ago
It's not for some reason Is this a router thing?
REEEEE
REEEEE•2w ago
idk what does the rest of the app look like? the part that renders the UserDetails component
hrtwrm
hrtwrmOP•2w ago
That is the entire UserDetails component
REEEEE
REEEEE•2w ago
.... Where do you use it Where do you do <UserDetails />
hrtwrm
hrtwrmOP•2w ago
import { A } from "@solidjs/router"; import { ParentComponent } from "solid-js"; import { UserDetails } from "./UserDetails"; import { WinnerTicker } from "./WinnerTicker"; const AppLayout: ParentComponent = (props) => { return ( <> <header class="@container flex items-center justify-between pt-2 pr-5 pb-2 pl-5"> <UserDetails /> </header> <WinnerTicker /> {props.children} </> ); } export default AppLayout; It's being used in a layout component that wraps the children
REEEEE
REEEEE•2w ago
And how is AppLayout used?
hrtwrm
hrtwrmOP•2w ago
import { Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; import { Suspense } from "solid-js"; import { initFlowbite } from 'flowbite'; import { onMount } from 'solid-js'; import "./app.css"; export default function App() { onMount(() => { initFlowbite(); }) return ( <Router root={props => ( <> <Suspense>{props.children}</Suspense> </> )} > <FileRoutes /> </Router> ); }
REEEEE
REEEEE•2w ago
Where is <AppLayout>?
hrtwrm
hrtwrmOP•2w ago
Well AppLayout is just a layout so it doesn't need to be placed directly because the directory structure is app/(layout)/
REEEEE
REEEEE•2w ago
Or is it a route right
hrtwrm
hrtwrmOP•2w ago
Within the app directory is the UserDetails And there is a (layout).tsx file
REEEEE
REEEEE•2w ago
hm okay, if you put other html in the UserDetails component, do you see it?
hrtwrm
hrtwrmOP•2w ago
Which is AppLayout Yes
REEEEE
REEEEE•2w ago
So the component is being rendered
hrtwrm
hrtwrmOP•2w ago
It is
REEEEE
REEEEE•2w ago
I have no clue
hrtwrm
hrtwrmOP•2w ago
same lol
REEEEE
REEEEE•2w ago
I saw you were using alias imports via ~
hrtwrm
hrtwrmOP•2w ago
The only thing I can think is this has something to do with the external api file
REEEEE
REEEEE•2w ago
maybe try relative?
hrtwrm
hrtwrmOP•2w ago
I moved the API creation logic inside the component and still getting the same issue
REEEEE
REEEEE•2w ago
It might not be resolving the import correctly and that's what's bugging it out Huh welp
hrtwrm
hrtwrmOP•2w ago
Yeah const userInfoResponse = await userInfo.response?.json(); I don't think the optional means anything here Or does anything
REEEEE
REEEEE•2w ago
What about removing some of the other stuff and just keep createExternalApi part
hrtwrm
hrtwrmOP•2w ago
Which stuff?
REEEEE
REEEEE•2w ago
const resource = async () => {
const externalApi = await createExternalApi();

return externalApi;
}
const resource = async () => {
const externalApi = await createExternalApi();

return externalApi;
}
hrtwrm
hrtwrmOP•2w ago
I can try that
REEEEE
REEEEE•2w ago
Or
const resource = async () => {
const externalApi = await createExternalApi();
console.log(externalApi)
return {};
}
const resource = async () => {
const externalApi = await createExternalApi();
console.log(externalApi)
return {};
}
hrtwrm
hrtwrmOP•2w ago
const resource = async () => { const URL = 'http://localhost:5000/' let extAPI = await ConnectToAPI(URL); console.log(extAPI); return JSON.stringify({}); } export const UserDetails = () => { const [data] = createResource(resource); return ( <> <Show when={data.loading}>Loading</Show> <Show when={data.error}>Error</Show> <Show when={data()}>{data()}</Show> </> ); } Works fine I get the {} where I think it should be
REEEEE
REEEEE•2w ago
do you see the console log? Try adding the userInfo part back
hrtwrm
hrtwrmOP•2w ago
No, actually
REEEEE
REEEEE•2w ago
what
hrtwrm
hrtwrmOP•2w ago
Oh wait It's logging it on the server Not the browser
REEEEE
REEEEE•2w ago
yeah it runs on the server first ssr
hrtwrm
hrtwrmOP•2w ago
Yes
REEEEE
REEEEE•2w ago
okay try adding userInfo back
hrtwrm
hrtwrmOP•2w ago
So yeah I am seeing it on the server
REEEEE
REEEEE•2w ago
but not the .json call one Just const userInfo = await externalApi.getUserInfo();
hrtwrm
hrtwrmOP•2w ago
Yes that works, I see the {} API logs
REEEEE
REEEEE•2w ago
try logging userInfo
hrtwrm
hrtwrmOP•2w ago
I am getting what I expect User { _restClient: undefined, _links: Map(0) {}, _lists: Map(0) {}, originalValues: Map(0) {}, response: undefined, username: '', email: '', lastName: '', firstName: '', dateOfBirth: 2025-04-10T23:05:52.864Z, accountBalance: 0 }
REEEEE
REEEEE•2w ago
Try doing the last part also it says response is undefined so so resource would always return undefined, idk why it works on save though
hrtwrm
hrtwrmOP•2w ago
This honestly could be a bug in that external api I will have to contact the author of it Because you're right, response is undefined When I save though it logs in the browser just fine When I refresh I get undefined on the server I guess I thought when it logged undefined it was still fetching the data But it only ever logs once On save it logs multiple times Why would it fetch once on refresh but multiple times on save?
REEEEE
REEEEE•2w ago
Not sure could just be an hmr thing
hrtwrm
hrtwrmOP•2w ago
what is hmr?
REEEEE
REEEEE•2w ago
hot module reload, the thing that lets you see your changes when you save
hrtwrm
hrtwrmOP•2w ago
I am assuming rendering but I dunno what it stands for Oh Right hmm hmr
REEEEE
REEEEE•2w ago
Does the createExternalApi stuff required something to be initialized beforehand?
hrtwrm
hrtwrmOP•2w ago
Yes
REEEEE
REEEEE•2w ago
maybe it's not ready when that component is rendered
hrtwrm
hrtwrmOP•2w ago
You have to connect to it and get an API instance back That might be true Where would I put it to make sure it's totally ready?
REEEEE
REEEEE•2w ago
Where do you create a api instance?
hrtwrm
hrtwrmOP•2w ago
In a file in a server directory It's just an async function that creates it and sends an instance back I will find the code
REEEEE
REEEEE•2w ago
hm
hrtwrm
hrtwrmOP•2w ago
import { ConnectToApi, Api } from "api-client"; let api: Api; const URL = 'http://localhost:5000/' export const createApi = async (): Promise<Api> => { const api = await ConnectToApi(URL); return api; } export const getApi = async (): Promise<Api> => { if (!api) { api = await createApi(); } return Api; } export const setApi = async (api: Api) => { api = api; } Pretty basic But I moved that ConnectToApi thing in the component and still the same result I guess I could prevent the whole app from rendering until there is an instance ready? I just don't think I should have to do that
REEEEE
REEEEE•2w ago
Do you even need this line? const userInfoResponse = await userInfo.response?.json();
hrtwrm
hrtwrmOP•2w ago
Well I have to return json, right? What else would I return?
REEEEE
REEEEE•2w ago
Return the userInfo object maybe It looks like it has the properties you'd want
hrtwrm
hrtwrmOP•2w ago
Server crashed and I get Error The value [object Object] of type "object" cannot be parsed/serialized.
REEEEE
REEEEE•2w ago
I see
hrtwrm
hrtwrmOP•2w ago
It's because it has methods on it
REEEEE
REEEEE•2w ago
You could just pull the data you want out of the object and return that Idk why the response part is undefined though
hrtwrm
hrtwrmOP•2w ago
Yeah this has to be an issue with the library because trying to pull an property out of the object and returning it does gives me the same issue
REEEEE
REEEEE•2w ago
What no way
hrtwrm
hrtwrmOP•2w ago
Yeah It's there when I save, not when I refresh I do get this game-selection:1 Unchecked runtime.lastError: The message port closed before a response was received. But not sure what it means Oh it's just chrome extensions, doesn't mean anything
REEEEE
REEEEE•2w ago
what if you log the response
hrtwrm
hrtwrmOP•2w ago
I did try another endpoint from that library that doesn't have to be authed to make a call and I had no issues I am really thinking it's this endpoint Or the way it's implemented
REEEEE
REEEEE•2w ago
maybe an auth issue?
hrtwrm
hrtwrmOP•2w ago
Possibly I will get with the library author and then get back to you I really don't think it's solid now that I've done a lot of testing Thanks for all of your help! After more playing with it I think this is an HMR issue On page refresh it's not mounting the component at all On save it does I am convinced this actually isn't the API library issue This is some sort of issue with rendering Oh wait I think I figured it out. On a page refresh the code is running in the browser and it's sending along the cookie it needs to authenticate. When it's being refreshed it's running on the server and the cookie is not there for it to be sent along and the call is failing. That's exactly what's happening. Because other non authed routes work.
import { createEffect, createResource, Show } from "solid-js";
import { ConnectToApi, User } from "api-client";

export default function UserDetails() {
const [userInfo] = createResource(async () => {
const api = await ConnectToApi('http://localhost:5000');
const userInfo = await api.getUserInfo();

return (await userInfo.response?.json()) as User;
});
debugger;

createEffect(() => {
console.log(userInfo);
console.log('entering user details');
});

return (
<>
<Show when={userInfo.loading}>Loading</Show>
<Show when={userInfo.error}>Error</Show>
<Show when={userInfo()}>{userInfo()?.username}</Show>
</>
);
}
import { createEffect, createResource, Show } from "solid-js";
import { ConnectToApi, User } from "api-client";

export default function UserDetails() {
const [userInfo] = createResource(async () => {
const api = await ConnectToApi('http://localhost:5000');
const userInfo = await api.getUserInfo();

return (await userInfo.response?.json()) as User;
});
debugger;

createEffect(() => {
console.log(userInfo);
console.log('entering user details');
});

return (
<>
<Show when={userInfo.loading}>Loading</Show>
<Show when={userInfo.error}>Error</Show>
<Show when={userInfo()}>{userInfo()?.username}</Show>
</>
);
}
This works when saving and I see it in the console in the browser When refreshing it does not
Madaxen86
Madaxen86•2w ago
You’ll need to proxy the cookies on the server. Incomplete mock:
function $authFetch(url: string, init?: RequestInit) {
if (!isServer) fetch(url, { ...init, credentials: "include" }); //include cookies on request
const cookie = getRequestEvent()?.request.headers.get("cookie") || ""; //get cookies from request and pass it them to the fetch call.
return fetch(`${import.meta.env.VITE_AUTH_HOST}${url}`, {
...init,
credentials: "include",
headers: {
...init?.headers,
cookie: cookie,
},
});
}
function $authFetch(url: string, init?: RequestInit) {
if (!isServer) fetch(url, { ...init, credentials: "include" }); //include cookies on request
const cookie = getRequestEvent()?.request.headers.get("cookie") || ""; //get cookies from request and pass it them to the fetch call.
return fetch(`${import.meta.env.VITE_AUTH_HOST}${url}`, {
...init,
credentials: "include",
headers: {
...init?.headers,
cookie: cookie,
},
});
}
hrtwrm
hrtwrmOP•2w ago
Why do I have to do this at all? Why can't I just make these calls on the client?
Madaxen86
Madaxen86•2w ago
Then you‘ll have to disable SSR. In the app.config.ts If you want to render on the server you have to be able to fetch in the server. With SSR the initial render is on the server once hydrated the app renders purely client side
hrtwrm
hrtwrmOP•2w ago
I created a discussion here on this: https://github.com/solidjs/solid/discussions/2467
GitHub
createResource and SSR ¡ solidjs solid ¡ Discussion #2467
I just started using SolidJS and I am very new. I am having a bit of trouble with createResource. Here is some example code: import { createEffect, createResource, Show } from "solid-js";...
hrtwrm
hrtwrmOP•2w ago
@Madaxen86 Is it common for folks to disable SSR in solid?
Madaxen86
Madaxen86•2w ago
If you don’t need SSR, then yes. If you want to create a page that’s SEO optimised, then absolutely not. In short: it depends
hrtwrm
hrtwrmOP•2w ago
I guess I should shouldn't use solidstart then and just stick to solid core?
Madaxen86
Madaxen86•2w ago
In app.config.ts you can set SSR:false and you have a classic SPA

Did you find this page helpful?