Optimizing Context prevents unnecessary re-renders when context values change.
Problem — single context:
1// ❌ All consumers re-render when any value changes2const AppContext = createContext({3 theme: "light",4 user: null,5 settings: {},6});
Solution 1 — Split contexts:
1const ThemeContext = createContext("light");2const UserContext = createContext(null);3const SettingsContext = createContext({});45function AppProvider({ children }) {6 const [theme, setTheme] = useState("light");7 const [user, setUser] = useState(null);8 const [settings, setSettings] = useState({});910 return (11 <ThemeContext.Provider value={theme}>12 <UserContext.Provider value={user}>13 <SettingsContext.Provider value={settings}>14 {children}15 </SettingsContext.Provider>16 </UserContext.Provider>17 </ThemeContext.Provider>18 );19}2021// Only ThemeContext consumers re-render when theme changes22function Header() {23 const theme = useContext(ThemeContext);24 return <header className={theme}>...</header>;25}
Solution 2 — Memoize value:
1function AppProvider({ children }) {2 const [theme, setTheme] = useState("light");34 const value = useMemo(() => ({5 theme,6 setTheme,7 }), [theme]);89 return (10 <ThemeContext.Provider value={value}>11 {children}12 </ThemeContext.Provider>13 );14}
Solution 3 — State reducer pattern:
1// Dispatch is stable, only state changes cause re-renders2const StateContext = createContext(null);3const DispatchContext = createContext(null);45function AppProvider({ children }) {6 const [state, dispatch] = useReducer(reducer, initialState);78 return (9 <DispatchContext.Provider value={dispatch}>10 <StateContext.Provider value={state}>11 {children}12 </StateContext.Provider>13 </DispatchContext.Provider>14 );15}
Solution 4 — Selective context:
1function useTheme() {2 const { theme } = useContext(AppContext);3 return theme;4}56// Component only re-renders when theme changes7function Header() {8 const theme = useTheme();9 return <header className={theme}>...</header>;10}