use-context-selector
?use-context-selector
是一个 React 库,用于优化 React Context 的性能。它基于标准的 React.createContext
和 useContext
,但提供了更细粒度的控制,让组件只在 Context 中特定部分发生变化时重新渲染,而不是整个 Context 值变化时都触发渲染。这种优化对于大型应用或频繁更新的 Context 非常有用。
在 React 中,使用 useContext
时,只要 Context 的值发生任何变化,所有依赖该 Context 的组件都会重新渲染,即使它们只关心 Context 中的一部分数据。use-context-selector
通过引入“选择器”(selector)的概念,允许你指定组件只订阅 Context 的某些特定部分,从而减少不必要的渲染。
React.createContext
和 useContext
。use-context-selector
依赖于 use-sync-external-store
(React 18+ 内置的工具),以确保状态同步和性能优化。
createContext
从 use-context-selector
创建一个 Context。Provider
提供 Context 值,和普通 Context 一样。useContextSelector
钩子,传入选择器函数,指定你关心的数据部分。下面是一个简单的例子,展示如何使用 use-context-selector
来优化 Context 的使用。
import { createContext, useContextSelector } from 'use-context-selector';
import React, { useState } from 'react';
// 1. 创建 Context
interface AppState {
count: number;
name: string;
}
const AppContext = createContext<AppState>({ count: 0, name: 'Default' });
// 2. Provider 组件
const AppProvider = ({ children }: { children: React.ReactNode }) => {
const [state, setState] = useState({ count: 0, name: 'Alice' });
return (
<AppContext.Provider value={state}>
{children}
<button onClick={() => setState((prev) => ({ ...prev, count: prev.count + 1 }))}>
Increment Count
</button>
<button onClick={() => setState((prev) => ({ ...prev, name: 'Bob' }))}>
Change Name
</button>
</AppContext.Provider>
);
};
// 3. 只关心 count 的组件
const CountDisplay = () => {
const count = useContextSelector(AppContext, (state) => state.count);
console.log('CountDisplay rendered');
return <div>Count: {count}</div>;
};
// 4. 只关心 name 的组件
const NameDisplay = () => {
const name = useContextSelector(AppContext, (state) => state.name);
console.log('NameDisplay rendered');
return <div>Name: {name}</div>;
};
// 5. 主应用
const App = () => (
<AppProvider>
<CountDisplay />
<NameDisplay />
</AppProvider>
);
export default App;
先安装 use-context-selector
:
npm installinstall use-contexttall use-context-selector
CountDisplay
会重新渲染(因为它订阅了 count
)。NameDisplay
不会重新渲染(因为 name
没变)。NameDisplay
会重新渲染(因为它订阅了 name
)。CountDisplay
不会重新渲染(因为 count
没变)。useContext
的对比如果使用标准的 React.createContext
和 useContext
,每次 state
更新(无论是 count
还是 name
),CountDisplay
和 NameDisplay
都会重新渲染,因为它们无法区分 Context 中哪些部分变了。
// 使用普通 useContext 的版本(对比用)
import React, { useContext, useState } from 'react';
const AppContext = React.createContext({ count: 0, name: 'Default' });
const CountDisplay = () => {
const { count } = useContext(AppContext {
const {
const { count } = useContext(AppContext);
console.log('CountDisplay rendered');
return <div>Count: {count}</div>;
};
const NameDisplay = () => {
const { name } = useContext(AppContext);
console.log('NameDisplay rendered');
return <div>Name: {name}</div>;
};
在这个版本中,任何状态变化都会导致两个组件都重新渲染。
use-context-selector
的优点useCallback
包裹,如果需要动态选择器)。use-context-selector
包,增加了项目依赖。