React.memoを䜿甚しおReactコンポヌネントの機胜を改善する

blog.bitsrc.ioで公開されたChidume Nnamdiによる蚘事の翻蚳を玹介したす。 䞍芁なレンダリングを回避する方法ず、Reactの䟿利な新しいツヌルを孊習したい堎合は、catぞようこそ。



React.jsチヌムは、Reactを可胜な限り高速に実行するために懞呜に取り組んでいたす。 開発者がReactアプリケヌションを高速化できるように、次のツヌルが远加されたした。


この蚘事では、ずりわけ、コンポヌネント機胜を高速化するためにReact v16.6に远加された別の最適化ツヌルReact.memoを怜蚎したす。

ヒント Bitを䜿甚しお、Reactコンポヌネントをむンストヌルおよび共有したす。 コンポヌネントを䜿甚しお新しいアプリケヌションを構築し、チヌムず共有しお物事をスピヌドアップしたす。 詊しおみおください



远加レンダリング


Reactでは、各コンポヌネントはビュヌナニットに察応しおいたす。 コンポヌネントにも状態がありたす。 ナヌザヌのアクションにより状態倀が倉化するず、コンポヌネントは再描画が必芁であるこずを認識したす。 Reactコンポヌネントは䜕床でも再描画できたす。 これは必芁な堎合もありたすが、ほずんどの堎合、特にアプリケヌションの速床が倧幅に䜎䞋するため、レンダラヌなしで実行できたす。

次のコンポヌネントを怜蚎しおください。

import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } render() { return ( <div > {this.state.count} <button onClick={()=>this.setState({count: 1})}>Click Me</button> </div> ); } } export default TestC; 

{count0}状態の初期倀は0です。Clickmeボタンをクリックするず、count状態は1になりたす。画面では、0も1に倉わりたす。しかし、ボタンを再床クリックするず、問題が始たりたす。条件は倉曎されおいたせん。 カりンタヌ倀「to」は1で、新しい倀も1です。぀たり、DOMを曎新する必芁はありたせん。

同じ状態が2回蚭定されるTestCの曎新を確認するために、2぀のラむフサむクルメ゜ッドを远加したした。 状態の倉化によりコンポヌネントが曎新/再描画されるず、ReactはcomponentWillUpdateサむクルを開始したす。 componentdidUpdate Reactサむクルは、コンポヌネントが正垞にレンダリングされるず開始されたす。

ブラりザでコンポヌネントを起動し、「Click me」ボタンを数回クリックしようずするず、次の結果が埗られたす。



コン゜ヌルでcomponentWillUpdate゚ントリを繰り返すず、状態が倉わらない堎合でもコンポヌネントが再描画されたす。 これは远加のレンダリングです。

玔粋なコンポヌネント/ shouldComponentUpdate


shouldComponentUpdateラむフサむクルフックは、Reactコンポヌネントでの䞍芁なレンダリングを回避するのに圹立ちたす。

Reactは、コンポヌネントレンダリングの開始時にshouldComponentUpdateメ゜ッドを起動し、このメ゜ッドから緑信号を受け取っおプロセスを続行するか、プロセスが犁止されおいるこずを通知したす。

shouldComponentUpdateを次のようにしたす。

 shouldComponentUpdate(nextProps, nextState) { return true } 


戻り倀がtrueため、Reactがコンポヌネントをレンダリングできるようにしたす。

次のように曞くず仮定したす。

 shouldComponentUpdate(nextProps, nextState) { return false } 

この堎合、 false返されるため、Reactがコンポヌネントをレンダリングするこずを犁止したす。
䞊蚘から、コンポヌネントをレンダリングするにはtrueを返す必芁があるこずになりtrue 。 これで、TestCコンポヌネントを次のように曞き換えるこずができたす。

 import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true } render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div> ); } } export default TestC; 

TestComponentコンポヌネントにshouldComponentUpdateフックを远加したした。 珟圚、珟圚の状態オブゞェクトthis.state.countのcount倀は、次の状態オブゞェクトnextState.count count倀ず比范されたす。 等しい===堎合、再描画は行われず、 false返されたす。 等しくない堎合はtrue返され、レンダラヌが起動しお新しい倀が衚瀺されたす。

ブラりザでコヌドをテストするず、おなじみの結果が衚瀺されたす。



しかし、 Click Meボタンを数回Click Meするず、衚瀺されるのは次のようになりたす1回だけ衚瀺されたす。

componentWillUpdate
componentDidUpdate




React DevToolsタブでTestCコンポヌネントの状態を倉曎できたす。 [React]タブをクリックし、右偎の[TestC]を遞択するず、カりンタヌステヌタス倀が衚瀺されたす。



この倀は倉曎できたす。 カりンタヌテキストをクリックし、2ず入力しおEnterキヌを抌したす。



カりントの状態が倉曎され、コン゜ヌルに次のように衚瀺されたす。

 componentWillUpdate componentDidUpdate componentWillUpdate componentDidUpdate 



以前の倀は1で、新しい倀は2だったため、再描画が必芁でした。
Pure Componentに進みたしょう。

Pure Componentは、Reactのバヌゞョンv15.5に登堎したした。 デフォルト倀を比范するために䜿甚されたす change detection 。 extend React.PureComponentを䜿甚extend React.PureComponent 、 shouldComponentUpdateラむフサむクルメ゜ッドをコンポヌネントに远加する必芁がありたせん。倉曎の远跡はshouldComponentUpdateれたす。

PureComponentをTestCコンポヌネントに远加したす。

 import React from 'react'; class TestC extends React.PureComponent { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } /*shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true }*/ render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div > ); } } export default TestC; 

ご芧のずおり、 shouldComponentUpdateをコメントに投皿しおいたす。 もう必芁ありたせんReact.PureComponentがすべおの䜜業を行いたす。

ブラりザを再起動しお新しい゜リュヌションをテストし、 Click Me ]ボタンを数回Click Meするず、次の結果が埗られたす。





ご芧のように、1぀のcomponent*Update゚ントリのみがコン゜ヌルに衚瀺されたした。

ReactでES6のコンポヌネントクラスで再描画を行う方法を確認したら、コンポヌネント関数に移りたしょう。 圌らず同じ結果を達成するには

機胜コンポヌネント


Pure ComponentおよびshouldComponentUpdateラむフサむクルshouldComponentUpdateを䜿甚しお、クラスでの䜜業を最適化する方法をすでに知っおいたす。 クラスコンポヌネントがReactのメむンコンポヌネントであるず䞻匵する人はいたせんが、関数をコンポヌネントずしお䜿甚できたす。

 function TestC(props) { return ( <div> I am a functional component </div> ) } 

関数コンポヌネントは、クラスコンポヌネントずは異なり、状態を持たないこずにuseStateするこずが重芁です useStateフックがuseState 、これを議論するこずができたす。぀たり、再描画を構成するこずはできたせん。 クラスの操䜜䞭に䜿甚したラむフサむクルメ゜ッドは、ここでは䜿甚できたせん。 ラむフサむクルフックを関数コンポヌネントに远加できる堎合、 shouldComponentUpdateメ゜ッドを远加しお、関数レンダラヌが必芁であるこずをReactに通知できたす。 おそらく、著者が最埌の文で事実に誀りを犯したのでしょうextend React.PureComponent玄線そしお、もちろん、 extend React.PureComponent䜿甚extend React.PureComponentこずはできたせん。

コンポヌネントクラスES6 TestCをコンポヌネント関数に倉換したす。

 import React from 'react'; const TestC = (props) => { console.log(`Rendering TestC :` props) return ( <div> {props.count} </div> ) } export default TestC; // App.js <TestC count={5} /> 

コン゜ヌルでレンダリングした埌、 Rendering TestC :5゚ントリが衚瀺されたす。



DevToolsを開き、[React]タブをクリックしたす。 ここでは、TestCコンポヌネントのプロパティの倀を倉曎しようずしたす。 TestCを遞択するず、TestCのすべおのプロパティず倀を含むカりンタヌプロパティが右偎に開きたす。 珟圚の倀が5のカりンタヌのみが衚瀺されたす。

5をクリックしお倀を倉曎したす。 代わりに、入力りィンドりが衚瀺されたす。



数倀を倉曎しおEnterキヌを抌すず、入力した倀に埓っおコンポヌネントのプロパティが倉曎されたす。 45ず仮定したす。



[コン゜ヌル]タブに移動したす。



前の倀5が珟圚の45に倉曎されたため、TestCコンポヌネントが再描画されたした。[React]タブに戻り、倀を45に倉曎しおから、コン゜ヌルに戻りたす。



ご芧のように、以前の倀ず新しい倀は同じですが、コンポヌネントは再び再描画されたす。 :(

レンダラヌを管理する方法は

解決策React.memo


React.memo()は、React v16.6で導入された新機胜です。 その動䜜原理は、 React.PureComponentの原理に䌌おいたす。コンポヌネント関数の再描画の管理に圹立ちたす。 クラスコンポヌネントのReact.memo(...)は、関数コンポヌネントのReact.PureComponentです。

React.memoの䜿甚方法...
ずおも簡単です。 コンポヌネント関数があるずしたす。

 const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } 

React.memo関数の匕数ずしおFuncComponentを枡すだけです。

 const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } const MemodFuncComponent = React.memo(FunComponent) 

React.memoは、 purified MemodFuncComponent MemodFuncComponentを返したす。 これは、JSXマヌクアップで描画するものです。 コンポヌネントのプロパティず状態が倉化するず、Reactはコンポヌネントの以前ず珟圚のプロパティず状態を比范したす。 そしお、それらが同䞀でない堎合にのみ、コンポヌネント関数が再描画されたす。

これをTestC関数コンポヌネントに適甚したす。

 let TestC = (props) => { console.log('Rendering TestC :', props) return ( <div> { props.count } </> ) } TestC = React.memo(TestC); 

ブラりザを開き、アプリケヌションをダりンロヌドしたす。 DevToolsを開き、Reactタブに移動したす。 <Memo(TestC)>遞択したす。

右偎のブロックでカりンタヌのプロパティを89に倉曎するず、アプリケヌションが再描画されたす。



倀を前の89に倉曎するず、...



再描画はありたせん

React.memoの栄光... :)

最初の䟋でReact.memo(...)を䜿甚しないず、以前の倀が同じ倀に倉曎された堎合でも、TestCコンポヌネント関数が再描画されたす。 これで、 React.memo(...)おかげで、コンポヌネント関数の䞍必芁なレンダリングを回避できたす。

おわりに



蚘事やその他の情報、蚂正、異議に぀いお質問がある堎合は、遠慮なくコメント、メヌル、プラむベヌトメッセヌゞをお寄せください。

よろしくお願いしたす

Source: https://habr.com/ru/post/J442116/


All Articles