# use-context-selector **Repository Path**: mirrors/use-context-selector ## Basic Information - **Project Name**: use-context-selector - **Description**: React-use-context-selector 是一个基于 Context API 的封装,应用于 useland 的 React useContextSelector ho - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: main - **Homepage**: https://www.oschina.net/p/react-use-context-selector - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-21 - **Last Updated**: 2025-09-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # use-context-selector [![CI](https://img.shields.io/github/actions/workflow/status/dai-shi/use-context-selector/ci.yml?branch=main)](https://github.com/dai-shi/use-context-selector/actions?query=workflow%3ACI) [![npm](https://img.shields.io/npm/v/use-context-selector)](https://www.npmjs.com/package/use-context-selector) [![size](https://img.shields.io/bundlephobia/minzip/use-context-selector)](https://bundlephobia.com/result?p=use-context-selector) [![discord](https://img.shields.io/discord/627656437971288081)](https://discord.gg/MrQdmzd) React useContextSelector hook in userland > [!IMPORTANT] > The goal of this library is to emulate the behavior of the React Context API with Concurrent React. > Many users try to use this library to avoid re-renders without needing to consider Concurrent React. > If you simply want to avoid re-renders, we recommend one of the following: > - [Zustand](https://github.com/pmndrs/zustand) > - [A naive implementation with useSyncExternalStore](https://github.com/dai-shi/use-context-selector/issues/109#issuecomment-1785147682) > - [Experimental react18-use](https://github.com/dai-shi/react18-use) > > [Learn more](https://github.com/dai-shi/use-context-selector/issues/149) ## 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](https://github.com/reactjs/rfcs/pull/119) is proposed and later proposed [Speculative Mode](https://github.com/reactjs/rfcs/pull/150) 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. ```bash 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](https://overreacted.io/a-complete-guide-to-useeffect/#why-usereducer-is-the-cheat-mode-of-hooks) intentionally. It also requires `useContextUpdate` to behave better in concurrent rendering. Its usage is optional and only required if the default behavior is unexpected. ## Usage ```javascript 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 (
Count1: {count1} {Math.random()}
); }; 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 (
Count2: {count2} {Math.random()}
); }; const StateProvider = ({ children }) => ( {children} ); const App = () => ( ); createRoot(document.getElementById('app')).render(); ``` ## API ### createContext This creates a special context for `useContextSelector`. #### Parameters * `defaultValue` **Value** #### Examples ```javascript 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\** * `selector` **function (value: Value): Selected** #### Examples ```javascript 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\** #### Examples ```javascript 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\** #### Examples ```javascript 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\, value: any, children: ReactNode}** * `$0.context` * `$0.value` * `$0.children` #### Examples ```javascript const valueToBridge = useBridgeValue(PersonContext); return ( {children} ); ``` ### useBridgeValue This hook return a value for BridgeProvider #### Parameters * `context` **Context\** ## 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](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children) 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](examples) folder contains working examples. You can run one of them with ```bash PORT=8080 pnpm run examples:01_counter ``` and open in your web browser. You can also try them directly: [01](https://stackblitz.com/github/dai-shi/use-context-selector/tree/main/examples/01_counter) [02](https://stackblitz.com/github/dai-shi/use-context-selector/tree/main/examples/02_person) [03](https://stackblitz.com/github/dai-shi/use-context-selector/tree/main/examples/03_suspense) ## Projects that use use-context-selector * [react-tracked](https://github.com/dai-shi/react-tracked) * [use-atom](https://github.com/dai-shi/use-atom) * [react-hooks-fetch](https://github.com/dai-shi/react-hooks-fetch)