Convert Figma logo to code with AI

dai-shi logouse-context-selector

React useContextSelector hook in userland

2,710
61
2,710
4

Top Related Projects

19,629

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

48,653

🐻 Bear necessities for state management in React

Official React bindings for Redux

27,618

Simple, scalable state management.

3,764

Manage state with style in every framework

Quick Overview

use-context-selector is a React hook library that provides a more efficient way to consume context in React applications. It allows components to subscribe to specific parts of a context, reducing unnecessary re-renders and improving performance in large-scale applications.

Pros

  • Improves performance by reducing unnecessary re-renders
  • Provides a more granular approach to context consumption
  • Compatible with existing React Context API
  • Lightweight and easy to integrate into existing projects

Cons

  • Requires additional setup compared to the standard Context API
  • May introduce complexity in simpler applications where performance optimization is not critical
  • Limited community support compared to more established libraries
  • Potential learning curve for developers unfamiliar with the concept of context selectors

Code Examples

  1. Basic usage of useContextSelector:
import { createContext } from 'react';
import { useContextSelector } from 'use-context-selector';

const MyContext = createContext({ foo: 'bar', count: 0 });

const MyComponent = () => {
  const count = useContextSelector(MyContext, state => state.count);
  return <div>{count}</div>;
};
  1. Creating a context with useContextSelector:
import { createContext } from 'use-context-selector';

const MyContext = createContext({ foo: 'bar', count: 0 });

const MyProvider = ({ children }) => (
  <MyContext.Provider value={{ foo: 'baz', count: 42 }}>
    {children}
  </MyContext.Provider>
);
  1. Using multiple selectors in a component:
import { useContextSelector } from 'use-context-selector';

const MyComponent = () => {
  const foo = useContextSelector(MyContext, state => state.foo);
  const count = useContextSelector(MyContext, state => state.count);
  return (
    <div>
      <p>{foo}</p>
      <p>{count}</p>
    </div>
  );
};

Getting Started

To use use-context-selector in your React project:

  1. Install the package:

    npm install use-context-selector
    
  2. Import and use in your components:

    import { createContext } from 'use-context-selector';
    import { useContextSelector } from 'use-context-selector';
    
    const MyContext = createContext(initialValue);
    
    // In a component
    const value = useContextSelector(MyContext, state => state.someProperty);
    
  3. Optionally, use the provided Provider component:

    import { Provider } from 'use-context-selector';
    
    const App = () => (
      <Provider value={contextValue}>
        {/* Your app components */}
      </Provider>
    );
    

Competitor Comparisons

19,629

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

Pros of Recoil

  • More powerful state management with atoms and selectors
  • Built-in support for asynchronous data fetching and caching
  • Better performance for large-scale applications with fine-grained updates

Cons of Recoil

  • Steeper learning curve due to new concepts and API
  • Requires wrapping the entire app with RecoilRoot
  • Potentially overkill for smaller applications

Code Comparison

use-context-selector:

const value = useContextSelector(MyContext, state => state.someValue);

Recoil:

const someValue = useRecoilValue(someAtom);

Summary

use-context-selector is a lightweight solution for optimizing React Context, ideal for smaller applications or those already using Context. Recoil, on the other hand, offers a more comprehensive state management system with advanced features, making it suitable for larger, complex applications. The choice between the two depends on the project's scale, performance requirements, and the team's familiarity with the respective APIs.

48,653

🐻 Bear necessities for state management in React

Pros of zustand

  • More flexible state management, not limited to React's Context API
  • Supports middleware and devtools for enhanced functionality
  • Can be used outside of React components (e.g., in utilities or services)

Cons of zustand

  • Steeper learning curve for developers familiar with React's built-in state management
  • Requires additional package installation and setup
  • May be overkill for simpler applications with basic state needs

Code Comparison

use-context-selector:

const MyComponent = () => {
  const value = useContextSelector(MyContext, state => state.value);
  return <div>{value}</div>;
};

zustand:

const useStore = create(set => ({
  value: 0,
  setValue: (newValue) => set({ value: newValue })
}));

const MyComponent = () => {
  const value = useStore(state => state.value);
  return <div>{value}</div>;
};

Both libraries aim to optimize performance in React applications by reducing unnecessary re-renders. use-context-selector focuses on enhancing React's Context API, while zustand provides a more comprehensive state management solution. use-context-selector is ideal for projects already using Context, whereas zustand offers greater flexibility and features for complex state management needs.

Official React bindings for Redux

Pros of react-redux

  • Widely adopted and well-established ecosystem
  • Robust middleware support for advanced features
  • Extensive documentation and community resources

Cons of react-redux

  • More boilerplate code required for setup and usage
  • Steeper learning curve for beginners
  • Potential performance issues with large state trees

Code Comparison

use-context-selector:

const value = useContextSelector(MyContext, state => state.value);

react-redux:

const value = useSelector(state => state.value);
const dispatch = useDispatch();

Key Differences

  • use-context-selector focuses on optimizing React's Context API, while react-redux is a full-fledged state management solution
  • use-context-selector has a simpler API and requires less setup
  • react-redux offers more advanced features like time-travel debugging and middleware support

Use Cases

  • use-context-selector: Ideal for smaller applications or components that need optimized context usage
  • react-redux: Better suited for large-scale applications with complex state management requirements

Performance Considerations

  • use-context-selector can provide better performance in certain scenarios by reducing unnecessary re-renders
  • react-redux may have performance overhead for simpler use cases but offers optimizations for larger applications

Community and Ecosystem

  • react-redux has a larger community and more third-party tools/libraries
  • use-context-selector is newer and has a growing community, but with fewer resources available
27,618

Simple, scalable state management.

Pros of MobX

  • More comprehensive state management solution with observables, actions, and computed values
  • Supports complex state structures and automatic tracking of dependencies
  • Works well for large-scale applications with intricate state management needs

Cons of MobX

  • Steeper learning curve due to its more extensive API and concepts
  • Requires more boilerplate code for setting up stores and actions
  • May be overkill for simpler applications or components

Code Comparison

use-context-selector:

const value = useContextSelector(MyContext, state => state.someValue);

MobX:

const store = useObserver(() => ({
  someValue: observable,
  updateValue: action(newValue => { this.someValue = newValue; })
}));

Key Differences

  • use-context-selector focuses on optimizing React Context performance
  • MobX provides a full-featured state management solution
  • use-context-selector is more lightweight and easier to integrate into existing React projects
  • MobX offers more powerful features for complex state management scenarios

Both libraries aim to improve state management in React applications, but they approach the problem from different angles. use-context-selector is a targeted solution for optimizing Context usage, while MobX offers a comprehensive state management ecosystem.

3,764

Manage state with style in every framework

Pros of signals

  • More flexible and can be used outside of React components
  • Potentially better performance for fine-grained updates
  • Simpler API with less boilerplate code

Cons of signals

  • Requires a different mental model compared to traditional React state management
  • May not integrate as seamlessly with existing React codebases
  • Limited ecosystem and community support compared to Context API

Code comparison

use-context-selector:

const MyComponent = () => {
  const value = useContextSelector(MyContext, state => state.value);
  return <div>{value}</div>;
};

signals:

const value = signal(0);
const MyComponent = () => {
  return <div>{value}</div>;
};

Key differences

  • use-context-selector focuses on optimizing React's Context API for performance
  • signals provides a more general-purpose reactive state management solution
  • use-context-selector maintains closer compatibility with standard React patterns
  • signals offers a more concise syntax for defining and using reactive state

Use cases

  • use-context-selector: Ideal for large React applications with complex state requirements
  • signals: Well-suited for applications that need fine-grained reactivity and performance optimizations

Community and ecosystem

  • use-context-selector has stronger ties to the React ecosystem
  • signals is gaining traction but has a smaller community and fewer integrations

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

use-context-selector

CI npm size discord

React useContextSelector hook in userland

Introduction

React Context and useContext is often used to avoid prop drilling, however it's known that there's a performance issue. When a context value is changed, all components that useContext will re-render.

To solve this issue, useContextSelector is proposed and later proposed Speculative Mode with context selector support. This library provides the API in userland.

Prior to v1.3, it uses changedBits=0 feature to stop propagation, v1.3 no longer depends on this undocumented feature.

Install

This package requires some peer dependencies, which you need to install by yourself.

npm install use-context-selector react scheduler

Notes for library authors:

Please do not forget to keep "peerDependencies" and note instructions to let users to install peer dependencies.

Technical memo

To make it work like original React context, it uses useReducer cheat mode intentionally.

It also requires useContextUpdate to behave better in concurrent rendering. Its usage is optional and only required if the default behavior is unexpected.

If you need a simpler solution, you can use useSyncExternalStore without any libraries. See an example.

Usage

import { useState } from 'react';
import { createRoot } from 'react-dom/client';

import { createContext, useContextSelector } from 'use-context-selector';

const context = createContext(null);

const Counter1 = () => {
  const count1 = useContextSelector(context, (v) => v[0].count1);
  const setState = useContextSelector(context, (v) => v[1]);
  const increment = () =>
    setState((s) => ({
      ...s,
      count1: s.count1 + 1,
    }));
  return (
    <div>
      <span>Count1: {count1}</span>
      <button type="button" onClick={increment}>
        +1
      </button>
      {Math.random()}
    </div>
  );
};

const Counter2 = () => {
  const count2 = useContextSelector(context, (v) => v[0].count2);
  const setState = useContextSelector(context, (v) => v[1]);
  const increment = () =>
    setState((s) => ({
      ...s,
      count2: s.count2 + 1,
    }));
  return (
    <div>
      <span>Count2: {count2}</span>
      <button type="button" onClick={increment}>
        +1
      </button>
      {Math.random()}
    </div>
  );
};

const StateProvider = ({ children }) => (
  <context.Provider value={useState({ count1: 0, count2: 0 })}>
    {children}
  </context.Provider>
);

const App = () => (
  <StateProvider>
    <Counter1 />
    <Counter2 />
  </StateProvider>
);

createRoot(document.getElementById('app')).render(<App />);

API

createContext

This creates a special context for useContextSelector.

Parameters

  • defaultValue Value

Examples

import { createContext } from 'use-context-selector';

const PersonContext = createContext({ firstName: '', familyName: '' });

useContextSelector

This hook returns context selected value by selector.

It will only accept context created by createContext. It will trigger re-render if only the selected value is referentially changed.

The selector should return referentially equal result for same input for better performance.

Parameters

  • context Context<Value>
  • selector function (value: Value): Selected

Examples

import { useContextSelector } from 'use-context-selector';

const firstName = useContextSelector(PersonContext, (state) => state.firstName);

useContext

This hook returns the entire context value. Use this instead of React.useContext for consistent behavior.

Parameters

  • context Context<Value>

Examples

import { useContext } from 'use-context-selector';

const person = useContext(PersonContext);

useContextUpdate

This hook returns an update function to wrap an updating function

Use this for a function that will change a value in concurrent rendering in React 18. Otherwise, there's no need to use this hook.

Parameters

  • context Context<Value>

Examples

import { useContextUpdate } from 'use-context-selector';

const update = useContextUpdate();

// Wrap set state function
update(() => setState(...));

// Experimental suspense mode
update(() => setState(...), { suspense: true });

BridgeProvider

This is a Provider component for bridging multiple react roots

Parameters

  • $0 {context: Context<any>, value: any, children: ReactNode}

    • $0.context
    • $0.value
    • $0.children

Examples

const valueToBridge = useBridgeValue(PersonContext);
return (
  <Renderer>
    <BridgeProvider context={PersonContext} value={valueToBridge}>
      {children}
    </BridgeProvider>
  </Renderer>
);

useBridgeValue

This hook return a value for BridgeProvider

Parameters

  • context Context<any>

Limitations

  • In order to stop propagation, children of a context provider has to be either created outside of the provider or memoized with React.memo.
  • Provider trigger re-renders only if the context value is referentially changed.
  • Neither context consumers or class components are supported.
  • The stale props issue exists in React 17 and below. (Can be resolved with unstable_batchedUpdates)
  • Tearing is only avoided if all consumers get data using useContextSelector. If you use both props and use-context-selector to pass the same data, they may provide inconsistence data for a brief moment. (02_tearing_spec fails)

Examples

The examples folder contains working examples. You can run one of them with

PORT=8080 pnpm run examples:01_counter

and open http://localhost:8080 in your web browser.

You can also try them directly: 01 02 03

Projects that use use-context-selector

NPM DownloadsLast 30 Days