Solid Context: Hierarchical Owner Graph Lookup Without Re-Render Propagation
- Last updated
- Prerequisites:
- SolidJS Owner Hierarchy
- React Context vs Solid Context
- solidjs
- context
- useContext
- owner-tree
- performance
- di
Read at your depth
The practical view
Solid's Context API is created using `createContext(defaultValue)` and consumed using `useContext(MyContext)`. You provide a value with `<MyContext.Provider value={...}>{children}</MyContext.Provider>`. Unlike React, **changing a Context Provider's value does NOT re-render intervening child components**, because Solid components run only once.
The same idea in other frameworks
`createContext` + `useContext` (triggers re-render on all consumers when value reference changes).Angular hierarchical `Injector` tree lookup with `inject(Token)`.`provide()` / `inject()` traversing the component instance parent chain.Svelte `setContext()` / `getContext()` walking component instance hierarchy.Legacy vs modern
React Context Re-render Cascade vs SolidJS Granular Context
React Context forces all consumers and intermediate components to re-render; Solid Context links direct signal subscribers with zero intermediate work.
<ThemeContext.Provider value={theme}> // ❌ Re-renders all consumers on change<ThemeContext.Provider value={theme}> // ✅ NEW: MiddleComponent NEVER re-runsInterview gotchas
Context
Interviewers test your understanding of Solid's run-once execution during Context provisioning.
The mechanical answer
Because the component body executing `<Context.Provider>` runs **only once**, passing `value={theme()}` resolves the signal immediately to its static initial string (e.g. `'light'`). Descendant components calling `useContext` will receive a static string that never updates. To pass reactive state through Context in Solid, you must pass the **signal accessor itself** (`value={theme}`) or a getter object (`value={{ get theme() { return theme(); } }}`).
Trap
Never call the signal getter `value={mySignal()}` inside the provider props; pass the accessor function `value={mySignal}`.
Context
Checks knowledge of Owner tracking context loss across asynchronous boundaries.
The mechanical answer
No. `useContext` relies on `getOwner()` to find the current active node in the Owner hierarchy. When execution crosses an asynchronous boundary (like `setTimeout` or after an `await`), the asynchronous task runs with `Owner === null`. `useContext` will fail to find the hierarchy and will return the default context value.
Trap
Always call `useContext()` synchronously at the top of your component or helper function, storing the reference before starting async operations.