序章
React 16.8のリリースにより、Reactアプリケーションで使用できる便利なフックがたくさんあります。 16.8で導入された組み込みフックの1つは、useMemo
です。 このフックは、アプリケーションのパフォーマンスを向上させる可能性があります。
この記事では、Reactで再レンダリングがどのように機能するか、それがReactアプリケーションにとって重要な考慮事項である理由、およびuseMemo
フックがそれを活用してアプリケーションのパフォーマンスを向上させる方法について説明します。 また、useMemo
がパフォーマンスの問題を引き起こす可能性がある場合についても学習します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- このチュートリアルを開始する前に、Reactの基本を理解してください。 React.js シリーズのコーディング方法に従って、Reactの詳細を学ぶことができます。
参照の平等と高価な操作
useMemo
が対処しようとしている2つの問題があります。
- 参照の平等
- 計算コストの高い操作
コンポーネントのライフサイクルでは、更新が行われると、Reactはコンポーネントを再レンダリングします。 Reactがコンポーネントの変更をチェックするとき、JavaScriptが同等性と浅い比較を処理する方法が原因で、意図しないまたは予期しない変更を検出する場合があります。 Reactアプリケーションでのこの変更により、不必要に再レンダリングされます。
さらに、その再レンダリングが長いfor loop
のようにコストのかかる操作である場合、パフォーマンスが低下する可能性があります。 高価な操作は、時間、メモリ、または処理のいずれかでコストがかかる可能性があります。 潜在的な技術的な問題に加えて、これはユーザーエクスペリエンスの低下につながる可能性があります。
一部が再レンダリングされると、コンポーネントツリー全体が再レンダリングされます。
したがって、Reactはこれを修正するためのmemo
のアイデアをリリースしました。
メモ化を理解する
メモ化は、メモ化する複雑な関数を渡す最適化手法です。 メモ化では、同じパラメーターが後で渡されたときに結果が「記憶」されます。
関数compute1 + 1
がある場合、2
を返します。 ただし、メモ化を使用している場合は、次に1
を関数で実行しても、それらは加算されません。 追加機能を実行せずに、答えが2
であることを覚えているだけです。
公式のReactドキュメントから、useMemo
の署名は次のようになります。
const memoizedValue = React.useMemo(() => computeExpensiveValue(a, b), [a, b]);
useMemo
は、関数と依存関係の配列を受け取ります。
依存関係は、関数の引数と同様に機能します。 依存関係のリストは、useMemo
が監視する要素です。変更がない場合、関数の結果は同じままです。 それ以外の場合は、関数を再実行します。 それらが変更されない場合、コンポーネント全体が再レンダリングされるかどうかは関係ありません。関数は再実行されず、代わりに保存された結果を返します。 これは、ラップされた関数が大きくて高価な場合に最適です。 これがuseMemo
の主な用途です。
useMemo
の例を作成する
これは、2つの計算コストの高い関数を使用するアイテムの配列にuseMemo
を使用する抽象的な例です。
const List = React.useMemo(() =>
listOfItems.map(item => ({
...item,
itemProp1: expensiveFunction(props.first),
itemProp2: anotherPriceyFunction(props.second)
})), [listOfItems]
)
上記の例では、useMemo
関数は最初のレンダリングで実行されます。 useMemo
は最初のレンダリングで実行されるため、高価な関数が完了するまでスレッドをブロックします。
useEffect
は、高価な関数が終了してエフェクトが発生するまでローディングスピナーをレンダリングできるため、最初はuseEffect
ほどきれいには見えません。
ただし、後続のレンダリングでは、listOfItems
が変更されない限り、高価な関数を再度実行する必要はありません。 useMemo
は、各関数の戻り値を「記憶」します。
これらの高価な関数が瞬時にレンダリングされるように見えます。 これは、高価な同期機能が1つか2つある場合に理想的です。
いつ使用するかuseMemo
最初にコードを記述してから、コードを再検討して、最適化できるかどうかを確認してください。 アプリケーションにuseMemo
を頻繁に実装すると、パフォーマンスが低下する可能性があります。
useMemo
の実装を検討している場合は、プロファイリングツールを使用して、コストのかかるパフォーマンスの問題を特定できます。 高価は、多くのリソース(メモリなど)を消費していることを意味します。 レンダリング時に関数で十分な数の変数を定義している場合は、useMemo
でメモ化するのが理にかなっています。
仕事に適切なフックを使用する
useMemo
の他に、useCallback
、useRef
、useEffect
もあります。
useCallback
フックはuseMemo
に似ていますが、メモ化された関数を返しますが、useMemo
には値を返す関数があります。
依存関係の配列が指定されていない場合、メモ化の可能性はなく、レンダリングごとに新しい値が計算されます。 その場合、useRef
フックを使用できます。 useMemo
がuseRef
よりも優れている点は、依存関係が変更された場合に再メモ化することです。
useMemo
に副作用や非同期呼び出しを発生させたくないでしょう。 そのような場合は、useEffect
を使用する必要があります。
結論
この記事では、useMemo
フックと、それをReactアプリケーションで使用するのが適切な場合について説明しました。
useMemo
は、高価な関数を「記憶」し、アプリケーションに変更が生じるたびに再レンダリングされないようにすることで、アプリケーションのパフォーマンスを向上させることができます。
このフックを使用するとパフォーマンスを向上させることができますが、使いすぎるとアプリケーションの速度が低下する可能性もあります。 フックを使用すればするほど、アプリケーションはより多くのメモリを割り当てる必要があります。
Reactのベストプラクティスの詳細については、DigitalOceanの How To Code inReact.jsシリーズ全体に従ってください。