Top Related Projects
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.
🐻 Bear necessities for state management in React
Official React bindings for Redux
Simple, scalable state management.
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
- 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>;
};
- 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>
);
- 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:
-
Install the package:
npm install use-context-selector
-
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);
-
Optionally, use the provided
Provider
component:import { Provider } from 'use-context-selector'; const App = () => ( <Provider value={contextValue}> {/* Your app components */} </Provider> );
Competitor Comparisons
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.
🐻 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
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.
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 designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
use-context-selector
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 withReact.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 anduse-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
Top Related Projects
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.
🐻 Bear necessities for state management in React
Official React bindings for Redux
Simple, scalable state management.
Manage state with style in every framework
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot