Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes done by setting store value in context of child component is not propagated back to parent during SSR rendering #8282

Closed
zlepper opened this issue Dec 29, 2022 · 3 comments · Fixed by #10086

Comments

@zlepper
Copy link

zlepper commented Dec 29, 2022

Describe the bug

If you have a pair of components, where one is intended to be used in slots of the parent components, and the components communicate by using a store in the context, then updates done to the store by the child component is not propagated back to the parent component during SSR, but only during client side rendering.

Concretely I'm using this to render a semi-dynamic table. When the client is doing the rendering, the table looks like this:
image
However, when done serverside, the output looks like this:
image

Once the client rendering kicks in, the table does update and renders correctly. However, it still causes a bit of a "flash" when things are corrected

One important things to note, the issue only occurs if the location of the child element in the DOM is after the read of the store. If the store is read after the child component has initialized, then the issue does not occur. That trick however cannot be used to solve my table case above, since the child component results in some styling that needs to change on the container element, and thus the child can only run after the parent.

Reproduction

The reproduction here is relatively minimal to keep things simple and illustrate the issue.

Stackblitz: https://stackblitz.com/edit/sveltejs-kit-template-default-wanpgy?file=src/lib/ChildComponent.svelte

The essential components are the ChildComponent and the ParentComponent. The +page.svelte only handles "invoking" the components.

ParentComponent.svelte:

<script>
	import { setContext } from 'svelte';
	import { writable } from 'svelte/store';

  const aStore = writable({value: 'set by parent'});
  setContext('a', aStore);
</script>
Before child component: {$aStore.value}<br>
<slot />
After child component {$aStore.value}

ChildComponent.svelte:

<script>
  import {getContext} from 'svelte';

  const parentStore = getContext('a');
  $parentStore.value = 'Set by child component'
</script>

Logs

No logs here, since this isn't an explicit error.

System Info

npx envinfo --system --binaries --browsers --npmPackages "{svelte,@sveltejs/*,vite}"
success Install finished in 1.534s


  System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 16.14.2 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 7.17.0 - /usr/local/bin/npm
  npmPackages:
    @sveltejs/adapter-auto: ^1.0.0 => 1.0.0 
    @sveltejs/kit: ^1.0.0 => 1.0.1 
    svelte: ^3.54.0 => 3.55.0 
    vite: ^4.0.0 => 4.0.3

Severity

serious, but I can work around it

Additional Information

Recording of the issue:
https://user-images.githubusercontent.com/1499810/209962702-1a83deaa-54a1-4439-9517-729bbb9926eb.mp4
You have to watch pretty carefully, since it only flashes the wrong text for a couple of ms.

@Conduitry
Copy link
Member

This has come up before and is the expected behavior. SSR constructs a string as it goes along. It does not construct an entire document tree and wait for everything to settle and then serialize it. This lets SSR run much faster, but has limitations like the one you've noted here. For this reason, it's recommended generally to have state passed down into components, not up.

@Conduitry Conduitry closed this as not planned Won't fix, can't repro, duplicate, stale Dec 29, 2022
@zlepper
Copy link
Author

zlepper commented Dec 29, 2022

While I do understand that part, how exactly would you solve these cases where using components rather than passing objects gives a much better developer ux?

I believe there is something to stop and undo, which is triggered when components causes errors, but I assume that happens at a Layout boundary then, and is not something general, or maybe I'm remembering that part wrong also.

Also the svelte docs mentions that using context + stores this way is supported as I read it, if you want some reactivity support.

Either way, thank you for the quick answer, I'll do a workaround instead :)

@hanszoons
Copy link
Contributor

I know this was closed as not planned, but this drove me nuts today.

The docs should at least make a note of this, as passing stores via parent component context is the recommended way to use stores with SSR safely right here: https://kit.svelte.dev/docs/state-management#using-stores-with-context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants