Prevent React Context Re-renders with Redux-Style Selectors
Source: Dev.to
The Problem
When using React Context, every component that consumes the context re‑renders whenever any value in that context changes.
import { createContext, useState } from 'react';
const AppContext = createContext();
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState('light');
const [notifications, setNotifications] = useState([]);
return (
{children}
);
}
import { useContext } from 'react';
function UserProfile() {
const { user } = useContext(AppContext);
return Hello, {user?.name}!;
}
Problem: UserProfile re‑renders when theme or notifications change, even though it only cares about user.
The Solution
use-context-hook lets you subscribe to only the values you need, using Redux‑style selectors.
import { createContextHook, useContextHook } from 'use-context-hook';
import { useState } from 'react';
// Create context
const AppContext = createContextHook();
// Provider stays the same
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState('light');
const [notifications, setNotifications] = useState([]);
return (
{children}
);
}
// Component ONLY re‑renders when `user` changes
function UserProfile() {
const user = useContextHook(AppContext, 'user');
return Hello, {user?.name}!;
}
Now UserProfile updates only when user changes.
Four Flexible Selector Patterns
1. String Selector (Single Value)
const user = useContextHook(AppContext, 'user');
2. Array Selector (Multiple Values)
const { user, theme } = useContextHook(AppContext, ['user', 'theme']);
3. Object Selector (Explicit Picks)
const { user, theme } = useContextHook(AppContext, {
user: 1,
theme: 1,
});
4. Function Selector (Redux‑Style)
// Pick specific fields
const { user, theme } = useContextHook(AppContext, (state) => ({
user: state.user,
theme: state.theme,
}));
// Or derive a value
const userName = useContextHook(AppContext, (state) => state.user?.name);
Real‑World Performance Impact
- Before: 50+ unnecessary re‑renders per user interaction
- After: Only the 2‑3 components that actually need to update
Example: a form’s re‑render count dropped from 47 to 3 when a user typed in a field.
How It Works (The Technical Bits)
useContextHookregisters a listener for the component based on the selector you provide.- When the context value changes, the library runs the selector on both the previous and new values.
- It performs a deep comparison of the selector results.
- A re‑render is triggered only if the selected values have changed.
This approach eliminates re‑renders for unchanged data, even with deeply nested objects.
TypeScript Support
interface AppContextType {
user: User | null;
theme: 'light' | 'dark';
notifications: Notification[];
}
const AppContext = createContextHook();
// Inferred as User | null
const user = useContextHook(AppContext, 'user');
// Inferred as { user: User | null; theme: 'light' | 'dark' }
const { user, theme } = useContextHook(AppContext, ['user', 'theme']);
Full type inference and safety are provided out of the box.
When Should You Use This?
Use Cases
- Large context objects with many values.
- Components need only specific parts of the context.
- Experiencing performance issues with the default Context API.
- Want Redux‑like selector patterns without adding Redux.
When Not to Use
- Context contains only 1‑2 values.
- All components require the entire context.
- Already using state‑management libraries such as Redux or Zustand that handle selective subscriptions.
Installation
npm install use-context-hook
# or
yarn add use-context-hook
# or
pnpm add use-context-hook
Live Examples
- String Selector:
- Array Selector:
- Object Selector:
- Redux‑Style Function Selector:
Comparison with Alternatives
| Library | Bundle Size | Selector Patterns | TypeScript | Re‑render Prevention |
|---|---|---|---|---|
| use-context-hook | ~2 KB | 4 patterns | Full | Yes |
| use-context-selector | ~3 KB | Function only | Partial | Yes |
| React Context (built‑in) | 0 KB | None | Built‑in | No |
| Redux | ~15 KB+ | Yes | Yes | Yes (but heavyweight) |
Wrapping Up
React Context is powerful, but its default behavior can cause unnecessary re‑renders in larger apps. use-context-hook provides:
- Tiny – ~2 KB minified
- Fast – Deep comparison only on selected values
- Type‑safe – Full TypeScript support
- Flexible – Four selector patterns
- Zero dependencies – Only React as a peer dependency
Use it to get Redux‑style selective subscriptions without the added complexity.
Links
- npm Package:
- GitHub Repository:
- Full Documentation: