Search code examples
solid-js

Using SolidJS context in async function


Is it possible to get the context value in an async function called from a component?

Even runWithOwner() gives me the default value of the context, not the enclosing value, after the first await.

  const Ctx = createContext('default');
  return <Ctx.Provider value={'not-default'} >{
    (() => {
      runWithOwner(getOwner()!, async () => {
        const f = async () => {};
        console.log('before', useContext(Ctx));
        await f();
        console.log('after', useContext(Ctx));
      });
      return '';
    })()
  }</Ctx.Provider >;

Tried enclosing the async call in runWithOwner()

Update: I 'solved' it by using signals instead of context. It's an import of a global variable either way, but signals work...

  const [Sig, setSig] = createSignal('default');
  const Ctx = createContext('default');
  const f = async (where: string) => {
    console.log(where, 'ctx', useContext(Ctx), 'sig', Sig());
  };
  return <Ctx.Provider value={setSig('not-default')} >{
    (() => {
      (async () => {
        await f('first');
        await f('broken');
      })();
      return '';
    })()
  }</Ctx.Provider >;

Solution

  • Context value is not a signal but an object property that resides on the current owner, so accessing it in an async function is not a problem and does not require runWithOwner.

    The problem is you are capturing the value inside an async scope before setting a new value through Ctx.Provider. Try accessing it through a variable, you will get the updated value.

    import { createContext, useContext } from 'solid-js';
    import { render } from 'solid-js/web';
    
    const Ctx = createContext('default');
    
    const Comp = () => {
      const cxt = useContext(Ctx);
      const run = () => {
        setTimeout(() => console.log(cxt), 1000);
        return null;
      }
      return run();
    };
    
    export const App = () => {
      return (
        <Ctx.Provider value={'not-default'} >
          <div>{useContext(Ctx)}</div>
          <Comp />
        </Ctx.Provider>
      );
    };
    
    render(() => <App />, document.body);
    

    https://playground.solidjs.com/anonymous/ab5ca23c-9551-416e-8e37-ef2c50d20ab1