peerreynders
peerreynders
SSolidJS
Created by lemonad on 4/19/2025 in #support
createEffect vs createEffect + on
The thing that tends to be overlooked by newcomers is fine-grained reactivity. fine-grain change will not trigger coarse-grained reactivity. The way tracking works, you only subscribe to the exact value that you actually access. “You accessed this value last time so I'll run you again the next time that value changes”. With primitive values it very clear when the value changes. When it comes to objects and arrays however “the value” is the object reference. If you don't explicitly access their content under a tracked context then Solid's tracking doesn't know that you are interested in changes of the content.
31 replies
SSolidJS
Created by lemonad on 4/19/2025 in #support
createEffect vs createEffect + on
If you make the following change:
export function SubComp(props: {
nearestPointConfig: NearestPointConfig | undefined;
}) {
createEffect((prev: NearestPointConfig | undefined) => {
const value = props.nearestPointConfig;
console.log('effect', value, value === prev);
return value;
}, undefined);

createEffect(
on(
() => props.nearestPointConfig,
(config) => {
console.log('effect 2', config);
}
)
);
return <div>SubComp</div>;
}
export function SubComp(props: {
nearestPointConfig: NearestPointConfig | undefined;
}) {
createEffect((prev: NearestPointConfig | undefined) => {
const value = props.nearestPointConfig;
console.log('effect', value, value === prev);
return value;
}, undefined);

createEffect(
on(
() => props.nearestPointConfig,
(config) => {
console.log('effect 2', config);
}
)
);
return <div>SubComp</div>;
}
You'll see this:
Timeout 1
effect {name: 'hello', areas: Array(1)} false
effect 2 {name: 'hello', areas: Array(1)}
Timeout 2
effect {name: 'hello', areas: Array(1)} true
Timeout 1
effect {name: 'hello', areas: Array(1)} false
effect 2 {name: 'hello', areas: Array(1)}
Timeout 2
effect {name: 'hello', areas: Array(1)} true
The first timeout replaced undefined with an entirely new object—therefore both effects fired. On the second timeout the first effect doesn't actually see a new object reference; it's identical to the last one—what it is reacting to is that the “guts” of the object have been replaced. The second effect only specifically is subscribed to changes to the object reference. Given that the object reference doesn't change on the second timeout the effect doesn't run.
31 replies
SSolidJS
Created by lemonad on 4/19/2025 in #support
createEffect vs createEffect + on
Any chance you could replicate it here? https://playground.solidjs.com/anonymous/d72eb037-7569-4225-b447-3faba1f7d58b I'm wondering whether it has something to do with how you modify the store. The first version will subscribe you to changes to anything along the path of the proxy necessary to get access to the final value. The second version will run the dependency function under the same circumstances but I believe that the effect function will only run when the config object reference changes.
31 replies
SSolidJS
Created by dtnc on 4/17/2025 in #support
Would this break reactivity?
Ripping apart an object and reassembling another just to access a single property isn't great form. If you require the “object ergonomics” then put in the work to create a reactive object with getters. As such it's the idiom that props use and is practised frequently.
export function useUserSession() {
return {
get user() {
return useSession()?.user;
},
get session() {
return useSession()?.session;
},
get isAuthenticated() {
return useSession()?.session.token;
},
// … getters for relevant statusProps …
};
}
export function useUserSession() {
return {
get user() {
return useSession()?.user;
},
get session() {
return useSession()?.session;
},
get isAuthenticated() {
return useSession()?.session.token;
},
// … getters for relevant statusProps …
};
}
Personally I start with utility functions and often don't get to the point where I have need for the object as a bag of methods semantics
function userFromSession() {
return useSession()?.user;
}

function sessionFromSession() {
return useSession()?.session;
}

function isAuthenticated() {
return Boolean(useSession()?.session.token);
}
function userFromSession() {
return useSession()?.user;
}

function sessionFromSession() {
return useSession()?.session;
}

function isAuthenticated() {
return Boolean(useSession()?.session.token);
}
All these really are, are derived signals. Alternately if your pattern of usage is to capture the session result inside memo/effect functions to be (synchronously) shared throughout their logic then use:
function userFrom(s: ReturnType<typeof useSession>) {
return s?.user;
}

function sessionFrom(s: ReturnType<typeof useSession>) {
return s?.session;
}

function isAuthenticated(s: ReturnType<typeof useSession>) {
return Boolean(s?.session.token);
}
function userFrom(s: ReturnType<typeof useSession>) {
return s?.user;
}

function sessionFrom(s: ReturnType<typeof useSession>) {
return s?.session;
}

function isAuthenticated(s: ReturnType<typeof useSession>) {
return Boolean(s?.session.token);
}
5 replies
SSolidJS
Created by dtnc on 4/17/2025 in #support
Clearing form after action in solid-start
You can specify an onComplete(submission) handler on the action options which could be leveraged in that capacity. I was added for @solidjs/router 0.15.0
3 replies
SSolidJS
Created by all_is_source_energy on 4/16/2025 in #support
Multi Layout Children
- children = default slot - props = named slots But then again perhaps you are talking about <Dynamic>. Perhaps you can describe your use case in a bit more detail.
2 replies
SSolidJS
Created by all_is_source_energy on 4/16/2025 in #support
Getting Page Title
Step back for a moment and think. If you have to get the title that way then you have a solution/architectural problem, not a Solid problem. Given that the app is driving the content of that title, any part that needs access to that information should already have it; if it does not then the current approach isn't fit for purpose and needs to be re-thought.
3 replies
SSolidJS
Created by Adam Goldstein on 4/13/2025 in #support
Solid Start Internal Fetch
Because of the Vinxi layer I believe $fetch doesn't work in Dev which means it doesn't really work.
https://discord.com/channels/722131463138705510/910635844119982080/1342244356844814498 The way I'm reading the room is that at this particular point in time “minimizing vinxi” is the top priority for the joint SolidStart/TanStackStart project. By extension fixing internal $fetch (or accepting PR's to the that regard) isn't really a priority until that “minimization effort” has been completed; $fetch being broken right now means it doesn't have to be fixed because nobody can rely on it right now anyway.
7 replies
SSolidJS
Created by Garzec on 4/15/2025 in #support
Need help understanding preload and file conventions
Just a preview to some stuff you're going to encounter. The preload function is not meant to be async. It's passed RoutePreloadFuncArgs so that it can synchronously derive arguments intended for query wrappers. While these wrappers are async, preload doesn't await them; the intent is to “warm” the query's so that the page being navigated to can get the response payload ASAP. The components on the page access query wrappers via createAsync. At this point the query wrappers serve request/response deduplication (don't make the mistake of thinking of it as a cache; it's not); multiple components on the page can access the response payload of the same query (each with its own createAsync()). Whether or not the query holds a resolved or rejected promise, it doesn't matter until at least one of the those consuming createAsyncs accessors is used somewhere; this is typically within the JSX. If the query just holds data, the JSX will render with that data. If the accessor however gets an Error, the error is thrown to the next highest ErrorBoundary which will then render it's fallback. You can use HttpStatusCode in JSX to set the status for an SSR page.
4 replies
SSolidJS
Created by slim (jamesc) on 4/13/2025 in #support
Multiple actions with different unique names seem to trigger each other's submission.result effects
The router has exactly one submissions queue. Submissions are matched by their url to the base of the action function. Given that both myAction1 and myAction2 use exactly the same action function goAction, their base URL is identical. The myAction1 and myAction2 names only come into play during hydration for forms. Other than that the actions are identical (in terms of the client/server relation they do exactly the same thing). So what is happening here is that submissions tracks goAction invocations, not myAction1 or myAction2 submissions. That is why in my example I used the submission arguments to discriminate between “action 1” and “action 2” submissions. Only when the effect saw that the outbound submission arguments were tied to the component's instance did it even subscribe to the next inbound result from that particularsubmission instance (and given that there may not be a result but an error that had to be subscribed for as well; finally the submission was cleared so it wouldn't hang around and be accidentally referenced later again). If I had to track multiple concurrent submissions I'd probably make the first submission argument a correlation identifier to cut down on potential confusion.
7 replies
SSolidJS
Created by Adam Goldstein on 4/13/2025 in #support
Solid Start Internal Fetch
As far as I can tell If you use - core use server functions and then - wrap those with API routes the need for an internal fetch mostly goes away because server code can use "use server" functions without overhead. Design-wise it's a re-framing from defaulting to API routes and instead focusing on server functions that can support API routes as well for non-SolidStart clients.
7 replies
SSolidJS
Created by dtnc on 4/14/2025 in #support
Why are both class and classList needed?
See: https://discord.com/channels/722131463138705510/722131463889223772/1247563450293551125 TL;DR: ignore classList and the functionality supported by it.
3 replies
SSolidJS
Created by slim (jamesc) on 4/13/2025 in #support
Multiple actions with different unique names seem to trigger each other's submission.result effects
You really can't understand this stuff until you start messing with useSubmissions (plural). https://stackblitz.com/edit/solidjs-templates-7u2yad?file=src%2Fapp.tsx
7 replies
SSolidJS
Created by slim (jamesc) on 4/13/2025 in #support
Multiple actions with different unique names seem to trigger each other's submission.result effects
function Submit(props: {
action: Action<[id: number], void, [id: number]>;
id: number;
}) {
const callAction = useAction(props.action);
const submission = useSubmission(props.action);
createEffect<number | undefined>((lastArg) => {
// Obtain submission argument
// OR subscribe to submission argument for next pass
const arg = submission.input?.[0];

if (!lastArg) {
if (arg !== props.id) return undefined;

// subscribe to result/error
const _result = submission.result;
const _error = submission.error;
return arg;
}

// result or error
const [result, error] = untrack(() => {
const resultTuple = [submission.result, submission.error];
submission.clear();
return resultTuple;
});

console.log('myAction error/result', props.id, error, result);

return undefined;
}, undefined);

return <button on:click={() => callAction(props.id)}>Go {props.id}</button>;
}
function Submit(props: {
action: Action<[id: number], void, [id: number]>;
id: number;
}) {
const callAction = useAction(props.action);
const submission = useSubmission(props.action);
createEffect<number | undefined>((lastArg) => {
// Obtain submission argument
// OR subscribe to submission argument for next pass
const arg = submission.input?.[0];

if (!lastArg) {
if (arg !== props.id) return undefined;

// subscribe to result/error
const _result = submission.result;
const _error = submission.error;
return arg;
}

// result or error
const [result, error] = untrack(() => {
const resultTuple = [submission.result, submission.error];
submission.clear();
return resultTuple;
});

console.log('myAction error/result', props.id, error, result);

return undefined;
}, undefined);

return <button on:click={() => callAction(props.id)}>Go {props.id}</button>;
}
7 replies
SSolidJS
Created by SkyLissh on 4/11/2025 in #support
SSR blank page
“View Page Source” after:
export default function Home() {
const myExample = createAsync(() => example(), { deferStream: true });

return {
/* same ol' JSX */
};
}
export default function Home() {
const myExample = createAsync(() => example(), { deferStream: true });

return {
/* same ol' JSX */
};
}
58 replies
SSolidJS
Created by SkyLissh on 4/11/2025 in #support
SSR blank page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<script>
// … hydration listener
</script>
<script>
// … seroval data already
</script>
<!--xs-->
<script
type="module"
src="…/node_modules/vinxi/runtime/client.js"
id="plugin-0"
></script>
<script type="module" src="/_build/@vite/client" id="vite-client"></script>
<style type="text/css" data-vite-dev-id="…/src/app.css" data-vite-ref="0">
/* … css */
</style>
<title data-sm="00000000100000300000120">Hello World</title>
</head>
<body>
<div id="app">
<!--!$e0000000--><a data-hk="000000001000001" href="/">Index</a
><a data-hk="000000001000002" href="/about">About</a
><style
data-hk="000000001000003000000"
type="text/css"
data-vite-dev-id="…/src/components/Counter.css"
data-vite-ref="0"
>
/* … css */
</style>
<main data-hk="0000000010000030000011">
<!--$--><!--/-->
<h1>Hello world!</h1>
<!--$--><button
data-hk="00000000100000300000130"
class="increment"
type="button"
>
Clicks:
<!--$-->0<!--/--></button
><!--/-->
<pre><!-- rendered JSON data --></pre>
<p>
Visit
<a href="https://start.solidjs.com" target="_blank"
>start.solidjs.com</a
>
to learn how to build SolidStart apps.
</p>
</main>
<!--!$/e0000000-->
</div>
<!--$-->
<script>
// …
</script>
<script type="module" async src="…/src/entry-client.tsx"></script>
<!--/-->
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<script>
// … hydration listener
</script>
<script>
// … seroval data already
</script>
<!--xs-->
<script
type="module"
src="…/node_modules/vinxi/runtime/client.js"
id="plugin-0"
></script>
<script type="module" src="/_build/@vite/client" id="vite-client"></script>
<style type="text/css" data-vite-dev-id="…/src/app.css" data-vite-ref="0">
/* … css */
</style>
<title data-sm="00000000100000300000120">Hello World</title>
</head>
<body>
<div id="app">
<!--!$e0000000--><a data-hk="000000001000001" href="/">Index</a
><a data-hk="000000001000002" href="/about">About</a
><style
data-hk="000000001000003000000"
type="text/css"
data-vite-dev-id="…/src/components/Counter.css"
data-vite-ref="0"
>
/* … css */
</style>
<main data-hk="0000000010000030000011">
<!--$--><!--/-->
<h1>Hello world!</h1>
<!--$--><button
data-hk="00000000100000300000130"
class="increment"
type="button"
>
Clicks:
<!--$-->0<!--/--></button
><!--/-->
<pre><!-- rendered JSON data --></pre>
<p>
Visit
<a href="https://start.solidjs.com" target="_blank"
>start.solidjs.com</a
>
to learn how to build SolidStart apps.
</p>
</main>
<!--!$/e0000000-->
</div>
<!--$-->
<script>
// …
</script>
<script type="module" async src="…/src/entry-client.tsx"></script>
<!--/-->
</body>
</html>
58 replies
SSolidJS
Created by SkyLissh on 4/11/2025 in #support
SSR blank page
instead of waiting for the data called in the queries?
SolidStart's default SSR behaviour is to render synchronously what it can and stream the rest in via seroval via a streaming response to the initial request (which I did mention earlier, here).
58 replies
SSolidJS
Created by SkyLissh on 4/11/2025 in #support
SSR blank page
Result from “View Page Source”.
58 replies
SSolidJS
Created by SkyLissh on 4/11/2025 in #support
SSR blank page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<script>
// … hydration listener
</script>
<script>
// … more
</script>
<!--xs-->
<script
type="module"
src="…/node_modules/vinxi/runtime/client.js"
id="plugin-0"
></script>
<script type="module" src="/_build/@vite/client" id="vite-client"></script>
<style type="text/css" data-vite-dev-id="…/src/app.css" data-vite-ref="0">
/* … css */
</style>
<title data-sm="00000000100000300000120">Hello World</title>
</head>
<body>
<div id="app">
<!--!$e0000000--><a data-hk="000000001000001" href="/">Index</a
><a data-hk="000000001000002" href="/about">About</a
><template id="pl-0000000010000030"></template
><!--pl-0000000010000030--><!--!$/e0000000-->
</div>
<!--$-->
<script>
// …
</script>
<script type="module" async src="…/src/entry-client.tsx"></script>
<!--/-->
</body>
</html>
<template id="0000000010000030"
><style
data-hk="000000001000003000000"
type="text/css"
data-vite-dev-id="../src/components/Counter.css"
data-vite-ref="0"
>
/* … css */
</style>
<main data-hk="0000000010000030000011">
<!--$--><!--/-->
<h1>Hello world!</h1>
<!--$--><button
data-hk="00000000100000300000130"
class="increment"
type="button"
>
Clicks:
<!--$-->0<!--/--></button
><!--/-->
<pre>
<!-- rendered JSON data -->
</pre>
<p>
Visit
<a href="https://start.solidjs.com" target="_blank">start.solidjs.com</a>
to learn how to build SolidStart apps.
</p>
</main></template
>
<script>
// … lots of seroval code streaming the async data in
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
<script>
// … hydration listener
</script>
<script>
// … more
</script>
<!--xs-->
<script
type="module"
src="…/node_modules/vinxi/runtime/client.js"
id="plugin-0"
></script>
<script type="module" src="/_build/@vite/client" id="vite-client"></script>
<style type="text/css" data-vite-dev-id="…/src/app.css" data-vite-ref="0">
/* … css */
</style>
<title data-sm="00000000100000300000120">Hello World</title>
</head>
<body>
<div id="app">
<!--!$e0000000--><a data-hk="000000001000001" href="/">Index</a
><a data-hk="000000001000002" href="/about">About</a
><template id="pl-0000000010000030"></template
><!--pl-0000000010000030--><!--!$/e0000000-->
</div>
<!--$-->
<script>
// …
</script>
<script type="module" async src="…/src/entry-client.tsx"></script>
<!--/-->
</body>
</html>
<template id="0000000010000030"
><style
data-hk="000000001000003000000"
type="text/css"
data-vite-dev-id="../src/components/Counter.css"
data-vite-ref="0"
>
/* … css */
</style>
<main data-hk="0000000010000030000011">
<!--$--><!--/-->
<h1>Hello world!</h1>
<!--$--><button
data-hk="00000000100000300000130"
class="increment"
type="button"
>
Clicks:
<!--$-->0<!--/--></button
><!--/-->
<pre>
<!-- rendered JSON data -->
</pre>
<p>
Visit
<a href="https://start.solidjs.com" target="_blank">start.solidjs.com</a>
to learn how to build SolidStart apps.
</p>
</main></template
>
<script>
// … lots of seroval code streaming the async data in
</script>
58 replies
SSolidJS
Created by SkyLissh on 4/11/2025 in #support
SSR blank page
I wouldn't expect to given that { deferStream: true } wasn't used. i.e. it would only be partially rendered.
58 replies