我们固定了反应上下文ð。使用选择器进行颗粒反应性
#javascript #网络开发人员 #react #redux

使用带有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的其他功能。其中的主要是选择器的支持。

让我们说我们构建了一个简单的计数器应用程序。但是,您需要两个计数器来跟踪两个计数器,而不是一个计数器。 firstCountersecondCounter。请记住,默认状态看起来像这样。

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

ð