createResource - SSR / SPA

moved conversation here @Christian
9 Replies
Christian
Christian13mo ago
Sounds good
Birk Skyum
Birk SkyumOP13mo ago
Link for context https://discord.com/channels/722131463138705510/910635844119982080/1176565292520972368 So, basically it appear that the createResource is running on the server now, and blocking the render. Do you have a repro of this? if you want to defer something to run on the client after the initial render, maybe the onMount is a good solution: https://docs.solidjs.com/references/api-reference/lifecycles/onMount it's usually a good place to intialize some libraries on the client, like diagrams etc.
Christian
Christian13mo ago
Going to just do some mock code, and also bare in mind this is quite jank because I was trying to fix the hydration error, which tells me I should probably just use createRouteData and useRouteData for it I'm presuming but I wanted to keep data fetching within the component. BUT The parent component is just some basic layout Parent
export default function() {
return (
...divs
<OurComponent/>
...divs
)
}
export default function() {
return (
...divs
<OurComponent/>
...divs
)
}
Then inside our component I'm trying to fetch an array of data
const [dataArr, setDataArr] = createSignal([])
const [data] = createResource(fetchData)

async function fetchData() {
try {
await new Promise((resolve, reject) => setTimeout(() => resolve(), 5000))
let res = await api('/myRoute', 'GET', null, false)
if (!Array.isArray(res.data)) return

return res
} catch (e) {
console.error(e)
return []
}
}

createEffect(() => {
setDataArr(data()?.data || []) // trying to render using a loop directly off the resource gave me hydration key error
})

export default function(props) {
return (
<Show when=(!data.loading} fallback={x}>
<For each={dataArr}>{(d) => renderSomething}</For>
</Show>
)
}
const [dataArr, setDataArr] = createSignal([])
const [data] = createResource(fetchData)

async function fetchData() {
try {
await new Promise((resolve, reject) => setTimeout(() => resolve(), 5000))
let res = await api('/myRoute', 'GET', null, false)
if (!Array.isArray(res.data)) return

return res
} catch (e) {
console.error(e)
return []
}
}

createEffect(() => {
setDataArr(data()?.data || []) // trying to render using a loop directly off the resource gave me hydration key error
})

export default function(props) {
return (
<Show when=(!data.loading} fallback={x}>
<For each={dataArr}>{(d) => renderSomething}</For>
</Show>
)
}
General gist of it. I could probably use onMount and do it all client sided which would probably fix the Hydration & the <Show> not working but wanted to see if I was just using createResource wrong when it comes to SSR since it seems to be acting up compared to when I had it on the SPA
Birk Skyum
Birk SkyumOP13mo ago
createResource / createRouteData is quite hard in general - it's definitely the areas I've spent the most time to get to work, and sometimes i've had to do quite some workarounds, so i personally look a lot forward to the new api here - also there is a solid-query (https://tanstack.com/query/latest/docs/solid/overview) which might help for more advanced cases.
Solid Query | TanStack Query Docs
The @tanstack/solid-query package provides a 1st-class API for using TanStack Query with SolidJS. Example
Christian
Christian13mo ago
Presuming this should also work fine with SolidStarts SSR?
Birk Skyum
Birk SkyumOP13mo ago
i don't really understand the purpose of the dataArr signal, since the setDataArr isn't used. The createResource returns a data signal already, so you can just use that
Christian
Christian13mo ago
was probably just a mock issue that I forgot to set it. But the point of it was to loop it since trying to use createResource with <Show> wasn't working and causing hydration errors when trying to loop it. I don't exactly understand why, let me change it to show it. Dude I am apparently really dumb. Okay, not sure what I messed up originally but that seemed to fix it despite it not working originally. Oh interestingly enough actually, when I remove the timeout for delaying it, I do get the hydration error back. This is with the original mock, all I changed was the fetchData function, and am now only using the createResource, so using data().data for the <For each={}>, and <Show when={!data.loading}/> Nothing else was changed, and it seems to be resolved when I just add a delay to the data fetching function, 1ms doesn't work, 500ms doesn't work, but 1s did work, so not sure what exactly is the issue. The error after I clear errors and retry seems to be alluding to the fact that <Show when={!data.loading}/> isn't working correctly or it seems to be saying it's done ahead of time, unsure, because it says cannot read properties of null (reading 'data') so when I'm doing data().data it's null, which it shouldn't hit unless data.loading is false. Changing it from <Show> to <Suspense> seems to make it work SLIGHTLY better, but it will still error every other refresh with the same issue of data() is undefined.
Christian
Christian13mo ago
No description
Christian
Christian13mo ago
Changing it to Show when={data()}/> seems to fix the hydration errors, but then its back to blocking the entire rendering, so then I triedShow when={!data.loading && data()}/> which has the same issue of it works on a setTimeout but not instant and causes hydration issues again For anyone that stumbles across it, switching the fetching to just be in the route and using routeData and useRouteData with createResource, and using a Suspense seemed to fix it, not exactly what I wanted but I'll manage.
Want results from more Discord servers?
Add your server