このチュートリアルでは、Reactにメモを実装する方法を説明します。記憶は、高価な機能呼び出しの結果を保存し、必要に応じてこれらのキャッシュ結果を返すことにより、パフォーマンスを向上させます。
以下をカバーします:
React.PureComponent
関数が子コンポーネントへのプロップとして渡される場合、React.memo()
が使用されていても、子コンポーネントが再レンダリングされます。これを回避するために、親コンポーネントがレンダリングするたびに機能が再現されるのを防ぐためにReact.memo()
反応アプリケーションには注意して暗記を使用する必要があります。コンポーネントが同じ出力を同じプロップに戻し、複数のUI要素(仮想DOMチェックがパフォーマンスに影響する)を含むか、多くの場合同じプロップを提供する場合に最適に機能します。 useCallback()
効率的なツリーアルゴリズムを使用して、ノードの更新は高速ですが、再描画は遅くなり、DOMが多数のUI要素を持っている場合、パフォーマンスに影響を与えます。したがって、Virtual DomがReactで導入されます。
これは、実際のDOMの仮想表現です。とにかく、アプリケーションの状態が変更されるたびに、Reactは実際のDOMを直接更新するのではなく、新しい仮想DOMを作成します。その後、Reactはこの新しい仮想DOMを以前に作成した仮想DOMと比較して、再描画する必要がある違いを見つけます。
これらの違いを使用して、仮想DOMは変更で実際のDOMを効果的に更新します。これにより、仮想DOMはUI要素とそのすべての子要素を単に更新するだけでなく、実際のDOMで必要な最小の変更のみを効果的に更新するため、パフォーマンスが向上します。
前のセクションでは、Virtual DOMを使用してPerformanceを改善するためにReactがDOM更新を効果的に実行する方法を見ました。このセクションでは、パフォーマンスをさらに向上させるためにメモリが必要な理由を説明するユースケースを見ていきます。
ボタンを備えた親クラスを作成して、Countという名前の状態変数をインクリメントします。親コンポーネントはまた、子コンポーネントを呼び出し、プロップを渡します。また、2つのクラスのレンダリング方法にconsole.log()ステートメントを追加しました。
この例の完全なコードは、codesandboxで入手できます。//Parent.js class Parent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState((prevState) => { return { count: prevState.count + 1 }; }); }; render() { console.log("Parent render"); return ( <div className="App"> <button onClick={this.handleClick}>Increment</button> <h2>Count: {this.state.count}</h2> <Child name={"joe"} /> </div> ); } } export default Parent;
親コンポーネントを渡した小道具を取得し、UIに表示する子のクラスを作成します:
親コンポーネントのボタンをクリックすると、カウント値が変更されます。これは状態の変更であるため、親コンポーネントのレンダリング方法が呼び出されます。
//Child.js class Child extends React.Component { render() { console.log("Child render"); return ( <div> <h2>Name: {this.props.name}</h2> </div> ); } } export default Child;
上記の例のカウントを次のサンドボックスで増やし、コンソールの出力を表示できます。
[CodeSandboxリンクはここに埋め込む必要がありますが、外部Webサイトにアクセスできないため、提供できません]
この出力から、親コンポーネントが再レンダーを再レンダーすると、子コンポーネントを再レンダリングする場合、子コンポーネントに渡されたプロップが変更されていなくても、子どものコンポーネントも再レンダリングすることがわかります。これにより、サブコンポーネントの仮想DOMが以前の仮想DOMとの差チェックを実行します。子コンポーネントに違いはないため - プロップはすべての再レンダーで同じであるため、実際のDOMは更新されません。<code>Parent render Child render Parent render Child render Parent render Child render</code>
実際のDOMを不必要に更新しないというパフォーマンスの利点はありますが、ここでは、新しい仮想DOMが作成され、子コンポーネントが実際に変更されていなくても、差チェックが実行されることがわかります。小さい反応コンポーネントの場合、このパフォーマンスは無視できますが、大きなコンポーネントの場合、パフォーマンスの影響は素晴らしいです。この再レンダリングと仮想DOMチェックを回避するために、メモリを使用します。
反応の暗記
Reactアプリケーションのコンテキストでは、記憶は親コンポーネントが再レンダーを再レンダーするたびに、小道具が変更されたときにのみ再レンダリングする技術です。小道具が変更されていない場合、レンダリングメソッドを実行するのではなく、キャッシュ結果を返します。レンダリングメソッドは実行されないため、仮想DOMと微分チェックは作成されません。したがって、パフォーマンスが向上します。
ここで、この不要な再レンダリングを避けるために、クラスと機能的な反応コンポーネントで暗記がどのように実装されているかを見てみましょう。
クラスコンポーネントにメモリを実装するには、React.PureComponent
を使用します。 React.PureComponent
shouldComponentUpdate()
<
子コンポーネントを以下に示すコードに変更します:
//Parent.js class Parent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState((prevState) => { return { count: prevState.count + 1 }; }); }; render() { console.log("Parent render"); return ( <div className="App"> <button onClick={this.handleClick}>Increment</button> <h2>Count: {this.state.count}</h2> <Child name={"joe"} /> </div> ); } } export default Parent;
親コンポーネントは変更されていません。さて、親コンポーネントでカウントを増加させると、コンソールの出力は次のとおりです。
最初のレンダリングでは、親と子のコンポーネントのレンダリング方法を呼び出します。
//Child.js class Child extends React.Component { render() { console.log("Child render"); return ( <div> <h2>Name: {this.props.name}</h2> </div> ); } } export default Child;
関数コンポーネントにメモリを実装
機能的な反応成分にメモリを実装するには、
と同様の作業を行う高次コンポーネント(HOC)です。 React.memo()
React.memo()
以下は、関数コンポーネントのコードです:PureComponent
この例の完全なコードは、次のサンドボックスで見ることができます。
<code>Parent render Child render Parent render Child render Parent render Child render</code>
//Child.js class Child extends React.PureComponent { // 将React.Component更改为React.PureComponent render() { console.log("Child render"); return ( <div> <h2>Name: {this.props.name}</h2> </div> ); } } export default Child;
の問題 上記の例では、子供のコンポーネントに
HOCを使用すると、親コンポーネントが再レンダリングされたとしても、子コンポーネントが再レンダリングされないことがわかります。ただし、注意すべき小さな問題は、子どものコンポーネントにプロップとして機能を渡すと、
を使用しても子コンポーネントが再レンダリングされることです。例を見てみましょう。<code>Parent render Child render Parent render Parent render</code>
React.memo()
React.memo()
React.memo()
では、子供のコンポーネントが再レンダリングされた原因は何ですか?答えは、親コンポーネントが再レンダーを再レンダーするたびに、新しいハンドラー関数が作成され、子コンポーネントに渡されるということです。これで、ハンドラー機能がレンダリングされるたびに再現されるため、子コンポーネントは、小道具と子どものコンポーネントのrerendersの浅い比較の場合、ハンドラーの参照が変更されていることがわかります。
次のセクションでは、この問題を解決する方法について説明します。
useCallback()
さらなる承認を避けるため子コンポーネントを再レンダリングする主な問題は、プログラム関数の再作成であり、これにより、子コンポーネントに渡される参照が変更されます。したがって、このレクリエーションを避ける方法が必要です。ハンドラーが再作成されていない場合、ハンドラーへの参照は変更されません。そのため、子コンポーネントはレンダリングされません。
親コンポーネントがレンダリングするたびに関数を再現しないようにするために、useCallback()
と呼ばれるReactフックを使用します。フックはReact 16に導入されました。フックの詳細については、Reactの公式フックのドキュメントをチェックしたり、「React Hooks:How To Wart and Build Your Own」をご覧ください。
useCallback()
フックは、コールバック関数と依存関係の2つのパラメーターを受け入れます。
次の例を考慮してくださいuseCallback()
例:
//Parent.js class Parent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState((prevState) => { return { count: prevState.count + 1 }; }); }; render() { console.log("Parent render"); return ( <div className="App"> <button onClick={this.handleClick}>Increment</button> <h2>Count: {this.state.count}</h2> <Child name={"joe"} /> </div> ); } } export default Parent;
ここで、useCallback()
はhandleClick()
関数に追加されます。 2番目のパラメーター[x,y]
は、空の配列、依存関係、または依存関係リストです。 2番目のパラメーターが変更された依存関係が変更されるたびに、handleClick()
関数は再作成されます。
useCallback()
で言及されている依存関係が変更されていない場合、コールバック関数の記憶されたバージョン(最初のパラメーターとして)が返されます。親の機能コンポーネントを変更して、子コンポーネントに渡されたハンドラーにuseCallback()
フックを使用します。
予防策
同じ小道具が与えられたときに同じ出力を返します
でUIをレンダリングする方法
なぜReact.memo()
をrederendします
React.PureComponent
プロップとしての関数を子供コンポーネントに渡すときに再レンダリングを避けるためにReact.memo()
useCallback()
反応の暗記についてのFAQ 以上がパフォーマンスを改善するために反応にメモを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。