Prevent React Context Re-renders with Redux-Style Selectors

Published: (December 7, 2025 at 09:48 AM EST)
3 min read
Source: Dev.to

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)

  • useContextHook registers 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

LibraryBundle SizeSelector PatternsTypeScriptRe‑render Prevention
use-context-hook~2 KB4 patternsFullYes
use-context-selector~3 KBFunction onlyPartialYes
React Context (built‑in)0 KBNoneBuilt‑inNo
Redux~15 KB+YesYesYes (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.

  • npm Package:
  • GitHub Repository:
  • Full Documentation:
Back to Blog

Related posts

Read more »