deferStream does not work

import { createAsync, Navigate, query } from "@solidjs/router";

const getShouldRedirect = query(async () => {
"use server";
return true;
}, "should-redirect");

export default function Home() {
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});

if (shouldRedirect()) return <Navigate href="/not-found" />;

return <>why are you here</>;
}
import { createAsync, Navigate, query } from "@solidjs/router";

const getShouldRedirect = query(async () => {
"use server";
return true;
}, "should-redirect");

export default function Home() {
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});

if (shouldRedirect()) return <Navigate href="/not-found" />;

return <>why are you here</>;
}
this works when coming from an initial request (server) but not from a <a> i expected it to work on client like server why is it like this?
45 Replies
Madaxen86
Madaxen862mo ago
You can't return early in solidjs components Try
return <Show when={shouldRedirect()}
fallback={<>why are you here</>}
>
<Navigate href="/not-found" />
</Show>
return <Show when={shouldRedirect()}
fallback={<>why are you here</>}
>
<Navigate href="/not-found" />
</Show>
exercise
exerciseOP2mo ago
can you explain "return early"?
zulu
zulu2mo ago
what it means, is that components are run once if you "return early" when something changes in the component body it is not going to rerun the component and allow you to return from a different return in the function you should have a single return in a component to avoid this
exercise
exerciseOP2mo ago
@Trader101 does that fix one of your issues? why would i need it to rerun
zulu
zulu2mo ago
ok, I might miss understood the original question I was answering in a more general sense is that your problem or Thomas problem who can verify what works ?
exercise
exerciseOP2mo ago
Madaxen's solution worked Thomas also needed deferStream redirects to work client-side i think
zulu
zulu2mo ago
ok, yeah so I think the single return advice is still good
exercise
exerciseOP2mo ago
yeah but i wanted it to actually click, not just keep it as a rule in my mind
zulu
zulu2mo ago
ok, if you remove the redirect logic I can help explain it in a more simple way, is that something you interested in ?
exercise
exerciseOP2mo ago
yes
zulu
zulu2mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Madaxen86
Madaxen862mo ago
Maybe this helps: The components body is not a reactive context - meaning it will not update on signal changes. Reactive contexts are: - functions - createMemo, createEffect, createComputed, ... - JSX By reading the signal here
if (shouldRedirect()) return <Navigate href="/not-found" />;
if (shouldRedirect()) return <Navigate href="/not-found" />;
The reactivity is broken. It's kind of the same as
function Comp(props) {
const redirect = props.redirect
}
function Comp(props) {
const redirect = props.redirect
}
exercise
exerciseOP2mo ago
i understand this, but why do i need reactivity in that example? i thought deferStream makes the value already available
zulu
zulu2mo ago
lol, i guess, I wasn't clear, I can explain the basic of why the double return in solid fail excludin the logic for the redirect / deferStream maybe @Madaxen86 can expand on that
exercise
exerciseOP2mo ago
like a signal that has an initial value:
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});
becomes:
createSignal(true)
createSignal(true)
Madaxen86
Madaxen862mo ago
Well deferStream means "don't stream a response to the client until the async is resolved" But it will not prevent the component to render with the default "undefined" value or whatever is in the query cache. And because reactivity is broken the rendered JSX of the initial render will be returned. In a nutshell: In Solid no early JSX returns. Make conditional JSX instead with Show or Switch + Match
exercise
exerciseOP2mo ago
so why does the page freeze with deferStream? because it waits until the value is not undefined?
zulu
zulu2mo ago
I think I get it, there is no reactivity in solid server side . whatever value you have in the signal that is what it will work with
exercise
exerciseOP2mo ago
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});
console.log({ shouldRedirect: shouldRedirect() });
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});
console.log({ shouldRedirect: shouldRedirect() });
this is logging undefined then true so, thats "reactivity" whatever reactivity means
zulu
zulu2mo ago
yeah, this is promise resolving. so i guess I still not getting the problem you are having
exercise
exerciseOP2mo ago
but even console.log("yes"); logs twice i have no problem, but i wanna understand regardless :)
zulu
zulu2mo ago
sure let me see if I can understand this ok I am starting to understand it
exercise
exerciseOP2mo ago
"But it will not prevent the component to render with the default "undefined" value or whatever is in the query cache." https://discord.com/channels/722131463138705510/1398301947760480306/1398348330882437250
zulu
zulu2mo ago
thinking ...
exercise
exerciseOP2mo ago
but that's exactly what deferStream does!
zulu
zulu2mo ago
ok I get it now
Thomas
Thomas2mo ago
I have 0 issues rn with solid but thanks 👍
exercise
exerciseOP2mo ago
yep, i'm trying to understand how both reactivity and deferStream work together, they seem contradictory to me, since deferStream guarantees for you that the query will have its value the first time its used
zulu
zulu2mo ago
ok follow me 1. components run once 2. shouldRedirect initial value is undefined 3. based on rule 1 Home() will run once, and only once 4. it will be falsy, because undefined and will return on return <>why are you here</> 5. deferStream, will hold off the response until the async is resolved
exercise
exerciseOP2mo ago
if that's true even with deferStream, my redirect shouldn't work, but its working
zulu
zulu2mo ago
6. but Home is already rendered
exercise
exerciseOP2mo ago
i'm basically doing "why is it working" here 🤣 not why its not working
zulu
zulu2mo ago
you broke the chain lol
exercise
exerciseOP2mo ago
. if its logging undefined, isn't it too late for the server to redirect?
zulu
zulu2mo ago
7. the redirect is probably at the client side
exercise
exerciseOP2mo ago
no, i checked
zulu
zulu2mo ago
just so i understand when you load the page do you see <>why are you here</>; ?
exercise
exerciseOP2mo ago
no
zulu
zulu2mo ago
you get the not found page
exercise
exerciseOP2mo ago
import { createAsync, Navigate, query } from "@solidjs/router";
import { Show } from "solid-js";

const getShouldRedirect = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 5000));

return true;
}, "should-redirect");

export default function Home() {
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});

return (
<Show when={shouldRedirect()} fallback={<>why are you here</>}>
<Navigate href="/not-found" />
</Show>
);
}
import { createAsync, Navigate, query } from "@solidjs/router";
import { Show } from "solid-js";

const getShouldRedirect = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 5000));

return true;
}, "should-redirect");

export default function Home() {
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});

return (
<Show when={shouldRedirect()} fallback={<>why are you here</>}>
<Navigate href="/not-found" />
</Show>
);
}
this is the working code but what i'm wondering about is
import { createAsync, Navigate, query } from "@solidjs/router";
import { Show } from "solid-js";

const getShouldRedirect = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 5000));

return true;
}, "should-redirect");

export default function Home() {
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});

console.log({ shouldRedirect: shouldRedirect() });

return (
<Show when={shouldRedirect()} fallback={<>why are you here</>}>
<Navigate href="/not-found" />
</Show>
);
}
import { createAsync, Navigate, query } from "@solidjs/router";
import { Show } from "solid-js";

const getShouldRedirect = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 5000));

return true;
}, "should-redirect");

export default function Home() {
const shouldRedirect = createAsync(() => getShouldRedirect(), {
deferStream: true,
});

console.log({ shouldRedirect: shouldRedirect() });

return (
<Show when={shouldRedirect()} fallback={<>why are you here</>}>
<Navigate href="/not-found" />
</Show>
);
}
how it's logging undefined and yet its not too late to redirect on the server that's all
zulu
zulu2mo ago
this logs on the server both undefined and true?
exercise
exerciseOP2mo ago
to test if it redirected on the server correctly:
console.log(await fetch("http://localhost:3000").then((res) => res.redirected));
console.log(await fetch("http://localhost:3000").then((res) => res.redirected));
yes
zulu
zulu2mo ago
ok , so looks like solid might be reevaluating the Home function ? unless it is the client making the api call ? but no actually
exercise
exerciseOP2mo ago
if it was just an innocent reevaluation it'd log true true instead of undefined true
zulu
zulu2mo ago
the log is outside true but put another log , it might be able to cache the async I am just speculating yeah ok so it does re run the function on the server mystery solved

Did you find this page helpful?