避免在React中进行不必要的渲染

202 阅读4分钟

避免React中不必要的渲染

优化你的React前端

obed amoasi

[

obed amoasi

](medium.com/@obedamoasi…)

[

1 天前-3

](betterprogramming.pub/avoid-unnec…

React的承诺是,当一个组件的道具或状态发生变化时,它将渲染该组件。

虽然这很好,但我们可能不希望所有的变化都能真正触发重新渲染。因此,我们需要很好地处理这些变化。我们将讨论一些情况,在这些情况下我们可以并且应该防止重新渲染的发生。

只传递需要的道具

不要向组件传递不必要的道具,只传递需要的东西。
以2个兄弟组件为例,一个是在屏幕上做动画的圆形组件,另一个是只输出圆形半径的文本组件。

这样做的问题是,尽管Info 不依赖于xCenteryCenter ,但当圆在屏幕上移动时,对它的改变将再次被重新渲染,从而导致它重新渲染。

为了解决这个问题,我们应该明确地只把需要的组件传递给子组件。Screen 组件应该被修改成下面这样。

这样,我们可以确保只有需要的道具被传递给组件。这就是我喜欢TypeScript的原因,它可以在不眨眼的情况下标记出初始代码。

使用React.Memo来避免重新渲染

无论如何,即使有了这些改进,我们仍然没有完成。

问题是,如果父组件因为道具或状态的变化而被重新渲染,那么子组件也可能被重新渲染,尽管它并不依赖于道具。

我们可以用记忆化来解决这个问题,这可以确保只有当组件的道具和状态发生变化时才会重新渲染。遵循这个模式,明智地使用React.memo

记忆化的组件将看起来像这样。

现在要使用它,我们反而要导入备忘化的版本。而且,我们甚至应该把父类也备忘化,以避免任何重新绘制,这样的话,如果父类的父类发生变化,Screen ,就不会重新绘制。虽然这取决于你的用例,但这可能不会发生。

使用回调来防止多次传递函数

让我们在屏幕上引入另一个组件--一个按钮,它只是坐在那里处理一些点击,做一些非常酷的事情。我们也不要忘了对它进行记忆,这样我们就能得到我们刚才讨论的很酷的功能。

现在,这里有一个问题。用于组件的变化检测是一个浅层的检测,它通常只对参考变化进行比较。

例如,考虑。

const object1 = {a:1}const object2 = {a:1}object1 == object2

这将给你带来错误。这是因为这两个对象指向不同的引用,因此,即使作为道具传递时也是不同的。

<MemoizedButton handleClick={() => {superClick(radius)}}/>

这里发生的情况是,无论何时Screen 组件被渲染,Button仍然会被重新渲染,只是因为一个新的handleClick 将被重新分配。

为了解决这个问题,我们需要把这个函数包在一个useCallback 钩子里。

React官方文档对此有很好的解释。

useCallback将返回一个记忆化的回调版本,只有当其中一个依赖关系发生变化时才会改变。当把回调传递给依赖引用平等的优化子组件时,这很有用,可以防止不必要的渲染
reactjs.org/docs/hooks-…

现在让我们继续讨论列表

始终使用唯一键来避免重新渲染大型列表。没有键是不好的,但是使用一个有可能在渲染筒之间改变的键也是不好的,如果不是 "更坏"。这里的目标是使用一个即使在组件被重新渲染时也不会改变的键。

例如,渲染一个文章卡片的列表,这可以是文章的lug,文章的URL,如果有的话,文章的数据库ID。如果是一个字符串的列表,如果它们是唯一的,字符串本身可以被认为是键。

一旦键是唯一的,React就会知道只渲染列表中变化的项目,而不是在列表中发生变化时渲染整个列表。现在我知道这是一个很大的问题,我将在另一篇文章中进一步解释。

用户资源是很难得的,所以不要使用是不必要的。这是我专注于优化React前端的系列文章的第一部分。谢谢你的阅读。