[]previous and next page

Exact semantics

Read the value in the component body (or in an effect) and keep it in a variable; do not call useContext inside handlers:

For agentsUpdated
  • The value is read once. The provider evaluates props.value when it is created. Pass an accessor or a store to provide something that changes (see Reactive values).
  • Children stay reactive. The provider returns an accessor of its children, so a children expression that reads signals still updates, and everything created inside sees the provided value.
  • Lookup follows owners. useContext reads the current owner, so it works while a component runs, inside effects and memos created there, and inside runWithOwner. After an await, in a timer, or in an event handler there is no owner, and the lookup falls back to the default value or throws.
  • Nearest wins. An inner provider shadows an outer one for its own subtree only.
  • No provider, no default: throws. useContext throws a ShadowError with code CONTEXT_MISSING. A context created with createContext() and no default value therefore means "a provider is required".
  • A default of undefined counts as no default. To make a context optional, give it a default that is not undefined, such as null.
  • Providers dispose with their owner. The provider creates a child owner; effects and cleanups created below it are disposed with the provider's parent.
  • On the server the provider builds its subtree once; nothing is reactive there.

Read the value in the component body (or in an effect) and keep it in a variable; do not call useContext inside handlers:

src/theme-button.tsxtsx
import { useContext } from "@shadow-js/core";
import { ThemeContext } from "./theme";

export function ThemeButton() {
  const theme = useContext(ThemeContext); // during setup
  return (
    <button type="button" onClick={() => console.log(theme)}>
      {theme}
    </button>
  );
}

export function Page() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemeButton />
    </ThemeContext.Provider>
  );
}