svelte

pattern of reactive svelte context state


What's a good way to pass reactive state that's derived from some $props() in grand-parent components?

For example, how do I pass derived states calculated from Grandparent's $props(), with components chain like Grandparent -> Parent -> Child. I can explicitly pass the derived states, but that's too cumbersome.

I tried using readable and setContext, but the readable does not update when $props() in Grandparent changes.


Solution

  • The most simple way would be to pass a function:

    import { setContext } from 'svelte';
    
    let { value } = $props();
    
    setContext('double', () => value * 2);
    
    // in descendant
    import { getContext } from 'svelte';
    
    const getDouble = getContext('double');
    

    Playground

    Any call of this getDouble function will be reactive, though the value is re-computed every time (here that would not be very expensive, since it is only a single multiplication). If you need the caching that $derived provides, you can extract the logic first:

    import { setContext } from 'svelte';
    
    let { value } = $props();
    
    const double = $derived(value * 2);
    setContext('double', () => double);
    

    For writable properties or if you do not like the function calls, you could use an object with a get/set property instead.