Solid.js: How to put useContext within a provider coming from an external event

1.9k Views Asked by At
const CounterContext = createContext();

export function CounterProvider(props) {
  const [count, setCount] = createSignal(0),
    store = [
      count
    ];

  return (
    <CounterContext.Provider value={store}>
      {props.children}
    </CounterContext.Provider>
  );
}

export function useCounter() { return useContext(CounterContext); }

I want to use this useCounter outside of the provider, after an external event like a setTimeout or an incoming Websocket message.

setTimeout(() => {
  const [count] = useCounter();
  createEffect(on(count, () => {
    console.log(count)
  }))
})

This seems like a bad idea, but I have this in my application code, and I don't know how to restructure my code to avoid this.

2

There are 2 best solutions below

0
On BEST ANSWER

Generally I would look at getting the useContext call under the provider if possible or under a effect under the main rendering that is guarded. Yes you could use more advanced APIs like runWithOwner, but it probably will lead to other hiccups later if things are structured in a way you wouldn't be able to do that.

Normally the fix involves creating a signal that wires up the dynamic behavior you want synchronously, and then triggers it by setting the signal from the timeout.

1
On

You can run asynchronous code with runWithOwner to have access to the component's context.

  // get component's owner
  const owner = getOwner();

  setTimeout(() => {
    // timeout happens after the owner has been assigned to null

    // in runWithOwner you have access to that owner's context
    runWithOwner(owner, () => {
      console.log(useContext(CounterContext));
    });
  });

Wrapping it with runWithOwner also makes the computations created within dispose alongside the component - if you create a computation outside a root, it will never be disposed.

Playground link: https://playground.solidjs.com/?hash=1366672288&version=1.3.16