React context api无需重新渲染

1,888 阅读2分钟

即使/当我们不直接在我们的项目中使用context时,大多数流行的库,如FormikRedux 等都有使用;如果使用的库没有绕过不需要的重新渲染问题的解决方案,我们应该在我们的组件中自己处理它

我面临的一个很大的性能问题, 最后由于这些重新渲染和解决这个问题,我不得不用滥用 React.memoReact.useCallbackReact.useMemo在大量的文件。
我在问我自己:如果我们可以去掉导致该问题的钩子而不是在我们的组件中添加很多东西呢?

所以答案是react-hooks-in-callback ,这 是一个 npm 包,可让您从回调挂载 react hook 并在回调本身中使用其状态

让我们创建一个index.jsx文件,我们将在其中定义我们的组件(AppTitleClicks

App: 这个组件将是我们将使用我们的context api并实现点击行为的包装器(在每个点击事件中,我们将增加点击值,而标题值将保持不变)

image.png

标题和点击: 虽然点击组件将在每个点击事件中重新呈现,但标题应该只呈现一次。为了检查这一行为,我们将在 Title 中定义一个变量countRef,该值在每次重新渲染时递增

image.png

最初组件看起来像这样

image.png

然后在点击 10 次之后,我们可以清楚地看到即使Title组件本身的 title 值仍然与之前相同(=> Title 组件重新渲染了 10 次),它的countRef值也发生了变化。

image.png

如果 Title 组件中有很多繁重的计算,这将产生性能问题,因此我们应该修复它:标准方法是使用React.memoReact.useCallbackReact.useMemo 。但这是一项耗时的操作,并且会增加您的代码行数。
相反,我们可以使用react-hooks-in-callback 包创建一个干净的上下文。

所以第一步是通过这个命令行安装它:

npm install react-hooks-in-callback

现在,为了有一个干净的上下文, 我们可以从react-hooks-in-callback导入createContext并使用它代替标准的React.createContext

image.png

使用新导入,无需更改App组件,只需更改消费者组件(TitleClicks)即可:我们只需要将 useContext替换为useContextSelector,这将帮助我们仅选择所需的状态。

在标题中: const title = useContextSelector((ctx) => ctx.title)  ;
在点击中:const clicks = useContextSelector((ctx) => ctx.clicks);

image.png

通过此更改,我们现在可以单击增量按钮并查看标题组件的行为

image.png

正如预期的那样,标题组件在 21 次点击后也没有重新渲染一次。
现在你看到了解决这个问题是多么简单(不管组件有多大,这个变化就是要用react-hooks-in-callback包中的干净的来替换标准的 React 上下文)

您可以在此sandbox找到示例。