使用带有React上下文的选择器textCon
引入了React中的上下文以解决一个问题。那就是道具钻探。但是它从来没有被用作国家经营。主要原因是渲染优化。上下文值的变化会导致整个子树重新渲染,这不是理想的,尤其是如果状态经常变化并且某些儿童组件的渲染价格昂贵。有一些解决方法,但这些方法也带来了自己的问题和局限性。像Redux这样的状态管理库从一开始就具有选择器的概念。有效地使用选择器可以显着提高反应应用的性能。在本文中,我将介绍一个名为 textcon 的库,我在React上下文和支持功能(例如选择器等)上构建了一个库。
https://github.com/mabdullahadeel/textcon
如果您想查看库的更多深入说明和使用。您可以观看此视频。
旁注。这个图书馆的灵感来自杰克·哈灵顿的this视频。强烈建议观看视频。
安装
# using npm
npm install textcon
# using yarn
yarn add textcon
# using pnpm
pnpm add textcon
用法
使用TextCon与Plain React上下文非常相似,并具有以下一般步骤。
- 使用默认状态和选项创建上下文。
- 带有提供商的包装组件树。
- 使用提供的钩子在组件中消耗状态。如果是平淡的反应上下文,则此挂钩是
useContext
,但是textcon
揭示了useStore
的其他功能。其中的主要是选择器的支持。
让我们说我们构建了一个简单的计数器应用程序。但是,您需要两个计数器来跟踪两个计数器,而不是一个计数器。 firstCounter
和secondCounter
。请记住,默认状态看起来像这样。
const defaultState = {
firstCounter: 0,
secondCounter: 0
}
让我们使用textcon
创建上下文。
import { createContextStore } from 'textcon';
const {Provider, useStore} = createContextStore({
firstCounter: 0,
secondCounter: 0
})
只需从textcon
导入createContextStore
并提供默认状态值。
此功能将返回对象。让我们破坏它使用;
- ************* 提供商 *************:需要包裹在要消耗状态的组件树上。
- *************** usestore ***************钩:此挂钩用于访问上下文中存储的状态。
现在让我们的父零件(<App/ >
)与提供商。
// ...
function App() {
return (
<Provider>
<div className="App">
Hello, World!
</div>
</Provider>
);
}
export default App;
现在,可以说我们有两个组成部分。
- 显示
firstCounter
值的组件 - 另一个要更新
firstCounter
值的组件
// ...
const Counter1Display = () => {
const {get: firstCounter} = useStore((state) => state.firstCounter);
return (
<div>
Counter 1: {firstCounter}
</div>
)
}
const Counter1Control = () => {
const { set } = useStore(() => false);
return (
<button onClick={() => {
set((prev) => ({
...prev,
firstCounter: prev.firstCounter + 1
}))
}}>
Increment Counter 1
</button>
)
}
// ...
在此片段中,我们定义了两个所需的组件。 Counter1Display
组件负责渲染上下文中存储的firstCounter
的当前值。 Counter1Control
组件呈现一个按钮,当单击时,将第一个计数器的值递增为1。
useStore
钩的工作原理与useSelector
钩在redux中的工作方式非常相似。传递给此挂钩的第一个参数是一个选择器函数,可用于选择整个状态(默认)或组件感兴趣的状态的一部分。
在Counter1Display
组件的情况下,我们只对firstCounter
值感兴趣,因为该组件将显示为该值。
// ...
const {get: firstCounter} = useStore((state) => state.firstCounter);
// ...
与redux的useSelector
钩子不同,useStore
by textcon
返回具有get
属性和set
setter功能属性的对象。 get
给出了提供给useSelector
的选择器返回的值。虽然set
可以使用像useState
钩中的react一样更新存储在上下文中的状态。
您可能注意到的一件事是回调函数传递给Counter1Control
组件中的useStore
。
// ...
const { set } = useStore(() => false);
// ...
由于Counter1Control
组件没有呈现任何反应性状态,因此可以将回调返回静态值作为选择器以防止重新租赁。
现在,让S渲染计数器组件。
function App() {
return (
<Provider>
<div className="App">
<Counter1Display />
<Counter1Control />
</div>
</Provider>
);
}
export default App;
以同样的方式,可以在上下文中访问和更新第二个计数器的状态。
使用动作
操作是预定义的函数,以更新上下文中存储的状态对象。可以在对象中提供动作作为createContextStore
函数的第二个参数。
让我们添加操作以更新计数器值。
import { createContextStore, ActionablePayload } from 'textcon';
const {Provider, useStore, useActions} = createContextStore({
firstCounter: 0,
secondCounter: 0
},
{
incrementFirstCounter: ({set, get}) => {
set((prev) => ({
...prev,
firstCounter: get().firstCounter + 1 // or prev.firstCounter + 1
}))
},
decrementFirstCounter: ({set, get}) => {
set((prev) => ({
...prev,
firstCounter: get().firstCounter - 1 // or prev.firstCounter + 1
}))
},
incrementBy: ({set, get}, action: ActionablePayload<number>) => {
set((prev) => ({
...prev,
firstCounter: get().firstCounter + action.payload
}))
}
})
操作可以触发using
useActions
钩子通过createContextStore
函数。
让我们更新我们的Counter1Control
组件以更新使用操作以更新上下文中的状态值存储。
// ...
const Counter1Control = () => {
const { incrementFirstCounter } = useActions();
return (
<button onClick={incrementFirstCounter}>
Increment Counter 1
</button>
)
}
// ...
更干净!以同样的方式,
// ...
const Counter1ControlByTen = () => {
const { incrementBy } = useActions();
return (
<button onClick={() => incrementBy(10)}>
Increment Counter 1 by 10
</button>
)
}
// ...
textcon
具有其他有用的功能,例如全球状态持续存在并订阅了反应组件之外的状态变化。
https://github.com/mabdullahadeel/textcon
ð