1. 単一の React コンポーネントのパフォーマンスの最適化
React はレンダリング パフォーマンスを向上させるために仮想 DOM を使用しますが、以前のレンダリング コンテンツがすべて破棄されるわけではありません。 Virtual DOM、DOM の助けを借りて、React は DOM ツリーへの最小限の変更を計算できます。これが React レンダリングの秘訣です。ただし、Virtual DOM は各 DOM の量を減らすことができます。仮想 DOM の計算と比較は最小限の処理であり、依然として複雑なプロセスです
もちろん、仮想 DOM の計算を開始する前にレンダリング結果が変わらないと判断できれば、実行する必要はありません。仮想 DOM の計算と比較が高速化されます。
レンダリング結果が変わらないと判断した場合、仮想DOMの計算を開始する前にコンポーネントのレンダリングを防ぐことができるため、パフォーマンスが向上します。当然、 shouldComponentUpdate( nextProp, nextState) を使用することを考えます
shouldComponentUpdate 関数は、「いつ再レンダリングが必要ないか」を決定するために render 関数の前に呼び出されます。
は、更新を続行するかどうかを決定するためにブール値を返します。デフォルトで true を返します。 false が返された場合、更新は中断されます。
shouldComponentUpdate(nextProp,nextState){ return (nextProp.completed !== this.props.completed) || (nextProp.text !== this.props.text) }
ただし、型が基本型である場合、値が同じである限り、上記の比較は単なる「浅い比較」です。が同じである場合、「浅い比較」
も 2 つが同じであると見なされます:
次に、 prop の型が複合オブジェクトの場合はどうなるでしょうか?
複雑なオブジェクトの場合、「浅い比較」メソッドは 2 つのプロパティが同じオブジェクトへの参照であるかどうかのみをチェックします。そうでない場合は、オブジェクトの内容がまったく同じであっても、それらは 2 つの異なるプロパティとみなされます。次に、「詳細比較」を使用します。ただし、オブジェクトの構造は予測できません。各フィールドに対して「詳細比較」を再帰的に実行すると、コードが複雑になるだけでなく、パフォーマンスの問題が発生する可能性があります。
したがって、前後のオブジェクトタイプのプロパティが同じであることを確認したい場合は、そのプロパティが同じJavaScriptオブジェクトを指していることを確認する必要があります:
<Foo styleProp = {{color: "red"}}>
const footStyle = {color: "red"};//确保这个初始化只执行一次,不要放在render函数中 <Foo styleProp = {footStyle}>
それが関数の場合はどうなるでしょうか?
<Foo onToggle={() => onToggleTodo(item.id)}/>
渡される小道具がたくさんある場合はどうすればよいですか?
そうですね~~React-Redux を使用している場合は、 shouldComponentUpdate のデフォルト実装があります。
React コンポーネントがロード、更新、アンロードされると、コンポーネントの一連のライフサイクル関数が呼び出されます。ただし、これらのライフサイクル関数は特定の React コンポーネント関数用であり、アプリケーションでは多数の React コンポーネントが上から下まで結合されており、それらの間のレンダリング プロセスはより複雑になります。
同じコンポーネントのレンダリングプロセスでも、ロードフェーズ、更新フェーズ、アンロードフェーズの 3 つのプロセスを考慮する必要があります
ロードフェーズでは、コンポーネントはとにかく一度完全にレンダリングされ、そこからすべてのサブコンポーネントがレンダリングされる必要がありますReact コンポーネントを下向きに読み込む場合は、React コンポーネントの読み込みライフ サイクルを実行する必要があるため、行うべき最適化はあまりありません。
アンインストールフェーズには、componentWillUnmount というライフサイクル関数が 1 つだけあります。この関数は、componentDidMount およびその他の仕上げ作業によって追加されたイベント処理と監視のみをクリーンアップするため、最適化の余地はありません。 React 更新フェーズ (調整) プロセスで
コンポーネント更新プロセスでは、更新された仮想 DOM が構築され、以前の仮想 DOM と比較され、相違点が特定され、最小限の DOM 操作で更新されます
調整プロセス: つまり、React の更新中に Virtual DOM の違いを見つけるプロセスは、通常、N 個のノードを持つ 2 つのツリー構造を比較するアルゴリズムです。デフォルトの比較を直接使用し、ノード数が多すぎる場合、時間計算量は O(n*3) になります。必要な操作が多すぎるため、React がこのアルゴリズムを使用することは不可能です
異なるノードタイプの場合
如果树形节点的类型不相同,那就意味着改动很大,直接认为原来的那个树形结构已经没用,可以扔掉,需要从新构建DOM树,原有的树形上的React组件便会经历“卸载”的生命周期;
也就是说,对于Virtual DOM树这是一个“更新”过程,但是却可能引发这个树结构上某些组件的“装载”和“卸载”过程
如:
更新前
<p> <Todos /> </p>
我们想要更新成这样:
<span> <Todos /> </span>
>1. 那么在作比较的时候,一看根节点原来是p,新的是span,类型就不一样了,那么这个算法就废弃之前的p包括里面的所有子节点,从新构建一个span节点和子节点;
>2. 很明显因为根节点不同就将所有的子节点从新构建,这很浪费,但是为了避免O(N*3)的时间复杂度,React这能选择这种比较简单、快捷的方法;
>3. 所以,作为开发者,我们一定要避免上面的浪费的情景出现
节点类型相同的情况
如果两个节点类型相同时,对于DOM元素,React会保留节点对应的DOM元素,只对其节点的属性和内容做对比,然后只修改更新的部分;
节点类型相同时,对于React组件类型,React做得是根据新节点的props去更新节点的组件实例,引发组件的更新过程;
在处理完根节点对比后,React的算法会对根节点的每一个子节点重复一样的操作
多个相同子组件的情况
如果最初组件状态为:
<ul> <TodoItem text = "First" /> <TodoItem text = "Second" /> </ul>
更新后为:
<ul> <TodoItem text = "First" /> <TodoItem text = "Second" /> <TodoItem text = "Third" /> </ul>
那么React会创建一个新的TodoItem组件实例,而前两个则进行正常的更新过程但是,如果更新后为:
<ul> <TodoItem text = "Zero" /> <TodoItem text = "First" /> <TodoItem text = "Second" /> </ul>
(这将暴露一个问题)理想处理方式是,创建一个新的TodoItem组件实例放在第一位,后两个进入自然更新过程
但是要让react按照这种方式,就必须找两个子组件的不同之处,而现有计算两个序列差异的算法时间是O(N*2),显然则
不适合对性能要求很高的场景,所以React选择了一个看起来很傻的办法,即挨个比较每个子组件;
React首先认为把text为First的组件的text改为Zero,Second的改为First,最后创建一个text为Second的组件,这样便会破原有的两个组件完成一个更新过程,并创建一个text为Second的新组件
这显然是一个浪费,React也意到,并提供了方克服,不过需要开发人员提供一点帮助,这就是key
Key的使用
key属性可以明确的告诉React每个组件的唯一标识
如果最初组件状态为:
<ul> <TodoItem key={1} text = "First" /> <TodoItem key={2} text = "Second" /> </ul>
更新后为:
<ul> <TodoItem key={0} text = "Zero" /> <TodoItem key={1} text = "First" /> <TodoItem key={2} text = "Second" /> </ul>
因为有唯一标识key,React可以根据key值,知道现在的第二和第三个组件就是之前的第一和第二个,便用原来的props启动更新过程,这样shouldComponentUpdate就会发生作用,避免无谓的更新;
注意:因为作为组件的唯一标识,所以key必须唯一,且不可变
下面的代码是错误的例子:
<ul> todos.map((item,index) => { <TodoItem key={index} text={item.text} /> }) </ul>
使用数组下标作为key值,看起来唯一,但不稳定,因为随着todos数组值的不同,同样一个组件实例在不同的更新过程中数组的下标完全可能不同,把下标当做可以就会让React乱套,记住key不仅要唯一还要确保稳定不可变
需要注意:虽然key是一个prop,但是接受key的组件不能读取key的值,因为key和ref是React保留的两个特殊prop,并没有预期让组将直接访问。
相关推荐:
以上がReact コンポーネントのパフォーマンス最適化方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。