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.
Any thoughts here would be greatly appreciated. I have been banging my head against the wall on this one.
110 Replies
Wrap the
data().username
in a fragment or any html elementUnfortunately even doing something like
<div>{data().username}</div>
is not working
Anyone else have any ideas?Can you share the "server/externalAPI" file?
@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?\
How are you rendering the component?
Yeah, so
data
is just undefined when I refresh the page
When I save, suddenly it's available
The code above is what I haveThat's all the code?
Yes
How does
UserDetails
get renderedWhat'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
I think the component isn't getting rendered properly so the hmr "fixes" it when you save
What would cause it not to be rendered properly?
Props destructuring possibly
some invisible error
Yeah the weird thing is there is no error
Are you able to reproduce the issue either in the playground or in a fresh project?
I don't think so, I think this is specific to me
Because it works otherwise with fetch
Hm, does
createExternalApi
use use server
?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 doesWhat if you wrap the resource with another function like
And I see it in the console, it logs data multiple times
Let me see
Crashed the development server lol
Progress lol
Wonder why
I dunno
Any errors?
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 errorsYeah I get that, but you said the dev server crashed so I was wondering if there were any errors
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 dataDid you try logging in an effect yet?
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?đ¤ˇââď¸
Is the resource function called? Like if you put a log in it, is it called?
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
Yeah so try putting some logs in the function and output each value for externalApi, userInfo, and userInfoResponse
and see what you get
On refresh nothing logs -- on file save it all logs
lol wth
It's not even running the function on a refresh
so maybe the component isn't being rendered
It's not for some reason
Is this a router thing?
idk what does the rest of the app look like?
the part that renders the UserDetails component
That is the entire UserDetails component
....
Where do you use it
Where do you do
<UserDetails />
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 childrenAnd how is AppLayout used?
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>
);
}
Where is
<AppLayout>
?Well
AppLayout
is just a layout so it doesn't need to be placed directly because the directory structure is app/(layout)/
Or is it a route
right
Within the app directory is the
UserDetails
And there is a (layout).tsx
filehm okay, if you put other html in the UserDetails component, do you see it?
Which is
AppLayout
YesSo the component is being rendered
It is
I have no clue
same
lol
I saw you were using alias imports via
~
The only thing I can think is this has something to do with the external api file
maybe try relative?
I moved the API creation logic inside the component and still getting the same issue
It might not be resolving the import correctly and that's what's bugging it out
Huh
welp
Yeah
const userInfoResponse = await userInfo.response?.json();
I don't think the optional means anything here
Or does anythingWhat about removing some of the other stuff and just keep createExternalApi part
Which stuff?
I can try that
Or
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 bedo you see the console log?
Try adding the userInfo part back
No, actually
what
Oh wait
It's logging it on the server
Not the browser
yeah it runs on the server first
ssr
Yes
okay try adding userInfo back
So yeah I am seeing it on the server
but not the
.json
call one
Just const userInfo = await externalApi.getUserInfo();
Yes that works, I see the
{}
API logstry logging userInfo
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
}
Try doing the last part
also it says response is undefined
so
so
resource
would always return undefined, idk why it works on save thoughThis 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?Not sure could just be an hmr thing
what is hmr?
hot module reload, the thing that lets you see your changes when you save
I am assuming rendering but I dunno what it stands for
Oh
Right
hmm hmr
Does the createExternalApi stuff required something to be initialized beforehand?
Yes
maybe it's not ready when that component is rendered
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?
Where do you create a api instance?
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 codehm
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 thatDo you even need this line?
const userInfoResponse = await userInfo.response?.json();
Well I have to return json, right?
What else would I return?
Return the userInfo object maybe
It looks like it has the properties you'd want
Server crashed and I get
Error
The value [object Object] of type "object" cannot be parsed/serialized.
I see
It's because it has methods on it
You could just pull the data you want out of the object and return that
Idk why the response part is undefined though
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
What no way
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 anythingwhat if you log the response
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
maybe an auth issue?
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.
This works when saving and I see it in the console in the browser
When refreshing it does not
Youâll need to proxy the cookies on the server. Incomplete mock:
Why do I have to do this at all? Why can't I just make these calls on the client?
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
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";...
@Madaxen86 Is it common for folks to disable SSR in solid?
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
I guess I should shouldn't use solidstart then and just stick to solid core?
In app.config.ts you can set SSR:false and you have a classic SPA