3 Star 0 Fork 0

Gitee 极速下载/use-context-selector

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/dai-shi/use-context-selector
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

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

The MIT License (MIT) Copyright (c) 2019 Daishi Kato Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

React-use-context-selector 是一个基于 Context API 的封装,应用于 useland 的 React useContextSelector ho 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
TypeScript
1
https://gitee.com/mirrors/use-context-selector.git
git@gitee.com:mirrors/use-context-selector.git
mirrors
use-context-selector
use-context-selector
main

搜索帮助