createAsync different values on client and server SSR issue

I'm trying to conditionally render components based on auth - think paywalled content. I have a server function that detects if user has logged in:
const _userLoggedIn = cache(async () => {
'use server'
const sessionData = await getSession()
const userId = sessionData.data.userId
if (userId) return true
return false
}, 'userLoggedIn')
const _userLoggedIn = cache(async () => {
'use server'
const sessionData = await getSession()
const userId = sessionData.data.userId
if (userId) return true
return false
}, 'userLoggedIn')
However, createAsync returns undefined leading nothing to be rendered on the server:
const userLoggedIn = createAsync(() => _userLoggedIn(), { deferStream: true })
console.log(userLoggedIn())
const userLoggedIn = createAsync(() => _userLoggedIn(), { deferStream: true })
console.log(userLoggedIn())
Server:
undefined
undefined
Client returns the expected value:
true
true
10 Replies
Mango Juicy
Mango JuicyOP4mo ago
Is there a way to ensure the same value on the server and client? Or should I tackle the paywall problem in a different way? Hmm maybe I need to wrap the component with <Suspense>? Seems to solve the issue if the value is true, but not when it's false
Brendonovich
Brendonovich4mo ago
It’ll always start as undefined on the server, since that console log runs before the server function completes The client will always receive the actual value since you’ve got deferStream
Mango Juicy
Mango JuicyOP4mo ago
The issue is this leads to Error: Hydration Mismatch It seems that SSR is using the undefined value to render instead of the actual intended value? Here is the JSX:
<Suspense>
<Switch>
<Match when={userLoggedIn() === false}>
<AlertDialog>
<AlertDialogTrigger as={props.dialogButton} {...props.dialogButtonProps}>
{dc()}
</AlertDialogTrigger>
<AlertDialogContent>
<div>
<AlertDialogTitle>Login</AlertDialogTitle>
<AlertDialogDescription>{props.description}</AlertDialogDescription>
</div>
<OauthProviders />
</AlertDialogContent>
</AlertDialog>
</Match>
<Match when={userLoggedIn() === true}>{c()}</Match>
</Switch>
</Suspense>
<Suspense>
<Switch>
<Match when={userLoggedIn() === false}>
<AlertDialog>
<AlertDialogTrigger as={props.dialogButton} {...props.dialogButtonProps}>
{dc()}
</AlertDialogTrigger>
<AlertDialogContent>
<div>
<AlertDialogTitle>Login</AlertDialogTitle>
<AlertDialogDescription>{props.description}</AlertDialogDescription>
</div>
<OauthProviders />
</AlertDialogContent>
</AlertDialog>
</Match>
<Match when={userLoggedIn() === true}>{c()}</Match>
</Switch>
</Suspense>
Brendonovich
Brendonovich4mo ago
Where are c and dc from?
Mango Juicy
Mango JuicyOP4mo ago
They are both child components
const dc = children(() => props.dialogChildren)
const c = children(() => props.children)
const dc = children(() => props.dialogChildren)
const c = children(() => props.children)
Brendonovich
Brendonovich4mo ago
Not sure if it matters but children will evaulate the children before rendering the rest of your component, i don't think you need it in this case
Mango Juicy
Mango JuicyOP4mo ago
Yeah, I think that was the cause. How did this solve the problem?
Brendonovich
Brendonovich4mo ago
Can't say for sure but there was probably a mismatch in which elements were being included in the page
lxsmnsyc
lxsmnsyc4mo ago
children and createMemo is quite known for producing hydration mismatches, but mainly children
Mango Juicy
Mango JuicyOP4mo ago
I found a GitHub issue detailing the children hydration mismatch: https://github.com/solidjs/solid-start/issues/1392
GitHub
[Bug?]: Hydration Mismatch when using children · Issue #1392 · so...
Duplicates I have searched the existing issues Latest version I have tested the latest version Current behavior 😯 Hello, I am getting a hydration mismatch error when attempting the following in ssr...
Want results from more Discord servers?
Add your server