Suggest an editImprove this articleRefine the answer for “How do you optimize working with context?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Optimizing work with context** comes down to making sure the provider's `value` reference only changes when its data actually changes, and that rarely changing and frequently changing pieces of state do not live in the same context. **Key point:** split context into small, domain-based pieces, memoize `value` with `useMemo`/`useCallback`, separate "changes often" from "changes rarely" into different contexts, and keep the Provider as close to its consumers as possible.Shown above the full answer for quick recall.Answer (EN)Image## 1) Split context into small pieces Do not put "everything at once" into one Provider. Split by domain - then when one value changes, only its consumers re-render. ```javascript <UserProvider value={user}> <ThemeProvider value={theme}> <I18nProvider value={i18n}> <App /> </I18nProvider> </ThemeProvider> </UserProvider> ``` ## 2) Memoize `value` The main rule: the `value` **reference should change only when its data changes**. ```javascript function ThemeProvider({ children }) { const [theme, setTheme] = useState<'light'|'dark'>('light'); const value = useMemo(() => ({ theme, setTheme }), [theme]); // good return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>; } ``` An anti-example (every render creates a new object -> all consumers get triggered): ```javascript <ThemeContext.Provider value={{ theme, setTheme }}> {/* bad */} ``` ## 3) Separate "changes often" from "changes rarely" Keep fast-changing data separate from stable data. ```javascript const CounterValueContext = createContext<number>(0); const CounterActionsContext = createContext<{ inc: () => void }>({ inc: () => {} }); function CounterProvider({ children }) { const [count, setCount] = useState(0); const inc = useCallback(() => setCount(c => c + 1), []); return ( <CounterActionsContext.Provider value={{ inc }}> <CounterValueContext.Provider value={count}> {children} </CounterValueContext.Provider> </CounterActionsContext.Provider> ); } ``` Now, changing `count` **does not** change the reference to `actions`, and consumers of the actions do not re-render. ## 4) Keep the Provider as close to consumers as possible Place the Provider around the part of the tree where the context is actually needed - fewer "subscribers" means fewer re-renders. ## 5) Use selectors (targeted reads) Out of the box, React re-renders all consumers, but you can narrow updates with context-selector libraries: - `use-context-selector` - Zustand/Jotai/Redux Toolkit with `useSelector` Example with `use-context-selector`: ```javascript import { createContext, useContextSelector } from 'use-context-selector'; const CartContext = createContext<{items: Item[]; total: number}>({items:[], total:0}); function TotalPrice() { const total = useContextSelector(CartContext, v => v.total); // re-renders only when total changes return <span>{total}</span>; } ``` ## 6) Do not pass "freshly created" objects/arrays If you need to hand out derived data - memoize it on the consumer side: ```javascript function ProductsList() { const { items } = useContext(ProductsContext); const visible = useMemo(() => items.filter(p => p.visible), [items]); return <List items={visible} />; } ``` ## 7) For global mutable state - `useReducer` `dispatch` is stable by reference -> convenient to pass through context. ```javascript const StoreContext = createContext<{state: State; dispatch: React.Dispatch<Action>}>(null!); function StoreProvider({ children }) { const [state, dispatch] = useReducer(reducer, initial); const value = useMemo(() => ({ state, dispatch }), [state]); // dispatch is stable return <StoreContext.Provider value={value}>{children}</StoreContext.Provider>; } ``` ## 8) External stores: `useSyncExternalStore` If you need a **thin subscription without re-rendering the whole context**, move the data to an external store and subscribe: ```javascript const subscribe = (listener: () => void) => store.subscribe(listener); const getSnapshot = () => store.getState().pieceYouNeed; const usePiece = () => useSyncExternalStore(subscribe, getSnapshot); ``` This gives "selective" updates out of the box. ## 9) Stabilize functions in `value` If `value` contains functions - wrap them in `useCallback` so the reference does not change for no reason. ```javascript const actions = useMemo(() => ({ save, remove }), [save, remove]); // where save/remove are useCallback ``` ## 10) Context is for "config", not for "counters" The less often a context changes, the better. Keep frequently updated pieces of state local (`useState` in components) or in an external store; context is for configuration, theming, permissions, locale, DI services, and so on.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.