S
SolidJS•6mo ago
heartworm

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•6mo ago
Wrap the data().username in a fragment or any html element
heartworm
heartwormOP•6mo ago
Unfortunately even doing something like <div>{data().username}</div> is not working Anyone else have any ideas?
Madaxen86
Madaxen86•6mo ago
Can you share the "server/externalAPI" file?
heartworm
heartwormOP•6mo 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•6mo ago
How are you rendering the component?
heartworm
heartwormOP•6mo 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•6mo ago
That's all the code?
heartworm
heartwormOP•6mo ago
Yes
REEEEE
REEEEE•6mo ago
How does UserDetails get rendered
heartworm
heartwormOP•6mo 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•6mo ago
I think the component isn't getting rendered properly so the hmr "fixes" it when you save
heartworm
heartwormOP•6mo ago
What would cause it not to be rendered properly?
REEEEE
REEEEE•6mo ago
Props destructuring possibly some invisible error
heartworm
heartwormOP•6mo ago
Yeah the weird thing is there is no error
REEEEE
REEEEE•6mo ago
Are you able to reproduce the issue either in the playground or in a fresh project?
heartworm
heartwormOP•6mo ago
I don't think so, I think this is specific to me Because it works otherwise with fetch
REEEEE
REEEEE•6mo ago
Hm, does createExternalApi use use server ?
heartworm
heartwormOP•6mo 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•6mo ago
What if you wrap the resource with another function like
const [data] = createResource(async () => await resource());
const [data] = createResource(async () => await resource());
heartworm
heartwormOP•6mo ago
And I see it in the console, it logs data multiple times Let me see Crashed the development server lol
REEEEE
REEEEE•6mo ago
Progress lol Wonder why
heartworm
heartwormOP•6mo ago
I dunno
REEEEE
REEEEE•6mo ago
Any errors?
heartworm
heartwormOP•6mo 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•6mo ago
Yeah I get that, but you said the dev server crashed so I was wondering if there were any errors
heartworm
heartwormOP•6mo 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•6mo ago
Did you try logging in an effect yet?
heartworm
heartwormOP•6mo 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•6mo ago
🤷‍♂️ Is the resource function called? Like if you put a log in it, is it called?
heartworm
heartwormOP•6mo 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•6mo ago
Yeah so try putting some logs in the function and output each value for externalApi, userInfo, and userInfoResponse and see what you get
heartworm
heartwormOP•6mo 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•6mo ago
so maybe the component isn't being rendered
heartworm
heartwormOP•6mo ago
It's not for some reason Is this a router thing?
REEEEE
REEEEE•6mo ago
idk what does the rest of the app look like? the part that renders the UserDetails component
heartworm
heartwormOP•6mo ago
That is the entire UserDetails component
REEEEE
REEEEE•6mo ago
.... Where do you use it Where do you do <UserDetails />
heartworm
heartwormOP•6mo 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•6mo ago
And how is AppLayout used?
heartworm
heartwormOP•6mo 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•6mo ago
Where is <AppLayout>?
heartworm
heartwormOP•6mo 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•6mo ago
Or is it a route right
heartworm
heartwormOP•6mo ago
Within the app directory is the UserDetails And there is a (layout).tsx file
REEEEE
REEEEE•6mo ago
hm okay, if you put other html in the UserDetails component, do you see it?
heartworm
heartwormOP•6mo ago
Which is AppLayout Yes
REEEEE
REEEEE•6mo ago
So the component is being rendered
heartworm
heartwormOP•6mo ago
It is
REEEEE
REEEEE•6mo ago
I have no clue
heartworm
heartwormOP•6mo ago
same lol
REEEEE
REEEEE•6mo ago
I saw you were using alias imports via ~
heartworm
heartwormOP•6mo ago
The only thing I can think is this has something to do with the external api file
REEEEE
REEEEE•6mo ago
maybe try relative?
heartworm
heartwormOP•6mo ago
I moved the API creation logic inside the component and still getting the same issue
REEEEE
REEEEE•6mo ago
It might not be resolving the import correctly and that's what's bugging it out Huh welp
heartworm
heartwormOP•6mo ago
Yeah const userInfoResponse = await userInfo.response?.json(); I don't think the optional means anything here Or does anything
REEEEE
REEEEE•6mo ago
What about removing some of the other stuff and just keep createExternalApi part
heartworm
heartwormOP•6mo ago
Which stuff?
REEEEE
REEEEE•6mo ago
const resource = async () => {
const externalApi = await createExternalApi();

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

return externalApi;
}
heartworm
heartwormOP•6mo ago
I can try that
REEEEE
REEEEE•6mo ago
Or
const resource = async () => {
const externalApi = await createExternalApi();
console.log(externalApi)
return {};
}
const resource = async () => {
const externalApi = await createExternalApi();
console.log(externalApi)
return {};
}
heartworm
heartwormOP•6mo 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•6mo ago
do you see the console log? Try adding the userInfo part back
heartworm
heartwormOP•6mo ago
No, actually
REEEEE
REEEEE•6mo ago
what
heartworm
heartwormOP•6mo ago
Oh wait It's logging it on the server Not the browser
REEEEE
REEEEE•6mo ago
yeah it runs on the server first ssr
heartworm
heartwormOP•6mo ago
Yes
REEEEE
REEEEE•6mo ago
okay try adding userInfo back
heartworm
heartwormOP•6mo ago
So yeah I am seeing it on the server
REEEEE
REEEEE•6mo ago
but not the .json call one Just const userInfo = await externalApi.getUserInfo();
heartworm
heartwormOP•6mo ago
Yes that works, I see the {} API logs
REEEEE
REEEEE•6mo ago
try logging userInfo
heartworm
heartwormOP•6mo 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•6mo 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
heartworm
heartwormOP•6mo 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•6mo ago
Not sure could just be an hmr thing
heartworm
heartwormOP•6mo ago
what is hmr?
REEEEE
REEEEE•6mo ago
hot module reload, the thing that lets you see your changes when you save
heartworm
heartwormOP•6mo ago
I am assuming rendering but I dunno what it stands for Oh Right hmm hmr
REEEEE
REEEEE•6mo ago
Does the createExternalApi stuff required something to be initialized beforehand?
heartworm
heartwormOP•6mo ago
Yes
REEEEE
REEEEE•6mo ago
maybe it's not ready when that component is rendered
heartworm
heartwormOP•6mo 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•6mo ago
Where do you create a api instance?
heartworm
heartwormOP•6mo 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•6mo ago
hm
heartworm
heartwormOP•6mo 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•6mo ago
Do you even need this line? const userInfoResponse = await userInfo.response?.json();
heartworm
heartwormOP•6mo ago
Well I have to return json, right? What else would I return?
REEEEE
REEEEE•6mo ago
Return the userInfo object maybe It looks like it has the properties you'd want
heartworm
heartwormOP•6mo ago
Server crashed and I get Error The value [object Object] of type "object" cannot be parsed/serialized.
REEEEE
REEEEE•6mo ago
I see
heartworm
heartwormOP•6mo ago
It's because it has methods on it
REEEEE
REEEEE•6mo ago
You could just pull the data you want out of the object and return that Idk why the response part is undefined though
heartworm
heartwormOP•6mo 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•6mo ago
What no way
heartworm
heartwormOP•6mo 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•6mo ago
what if you log the response
heartworm
heartwormOP•6mo 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•6mo ago
maybe an auth issue?
heartworm
heartwormOP•6mo 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•6mo 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,
},
});
}
heartworm
heartwormOP•6mo ago
Why do I have to do this at all? Why can't I just make these calls on the client?
Madaxen86
Madaxen86•6mo 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
heartworm
heartwormOP•6mo 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";...
heartworm
heartwormOP•6mo ago
@Madaxen86 Is it common for folks to disable SSR in solid?
Madaxen86
Madaxen86•6mo 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
heartworm
heartwormOP•6mo ago
I guess I should shouldn't use solidstart then and just stick to solid core?
Madaxen86
Madaxen86•6mo ago
In app.config.ts you can set SSR:false and you have a classic SPA

Did you find this page helpful?