DEV Community

Cover image for Stop Over-Rerenders: Smarter State Sharing in React with `useContextSelector`
sperez927
sperez927

Posted on

Stop Over-Rerenders: Smarter State Sharing in React with `useContextSelector`

๐Ÿšซ Problem: Global Context = Silent Performance Killer

React's Context API is often misused as global state. It works - until updates to one part of the state cause every consumer to re-render.
We ran into this on a dashboard with many components reading shared filters. One toggle = full tree re-render. Not okay.

โœ… Solution: Replace useContext with useContextSelector

Install the context-selector lib:

npm install use-context-selector

Then replace:

const { filters } = useContext(AppContext);

With:

const filters = useContextSelector(AppContext, ctx => ctx.filters)

Now only the components that care about filters will re-render.

๐Ÿงช Working Example

import {
  createContext,
  useContextSelector,
  useContext,
} from 'use-context-selector';
import React, { useState } from 'react';

const AppContext = createContext(null);

function Provider({ children }) {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  const value = { count, setCount, text, setText };
  return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
}

function CountDisplay() {
  const count = useContextSelector(AppContext, ctx => ctx.count);
  console.log('Render: CountDisplay');
  return <div>Count: {count}</div>;
}

function TextDisplay() {
  const text = useContextSelector(AppContext, ctx => ctx.text);
  console.log('Render: TextDisplay');
  return <div>Text: {text}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Toggling one field no longer rerenders both. Easy win, real speed boost.

๐Ÿง  Takeaway

  • Avoid useContext for frequently-updated state
  • useContextSelector = scoped updates + happy FPS

Top comments (0)

OSZAR »