Help us understand the problem. What is going on with this article?

React hooksを基礎から理解する (useMemo編)

React hooksとは

React 16.8 で追加された新機能です。
クラスを書かなくても、 stateなどのReactの機能を、関数コンポーネントでシンプルに扱えるようになりました。

useMemoとは

useMemoは値を保存するためのhookで、何回やっても結果が同じ場合の値などを保存(メモ化)し、そこから値を再取得します。
不要な再計算をスキップすることから、パフォーマンスの向上が期待出来ます。
useCallbackは関数自体をメモ化しますが、useMemoは関数の結果を保持します。

メモ化とは

メモ化とは同じ結果を返す処理について、初回のみ処理を実行記録しておき、値が必要となった2回目以降は、前回の処理結果を計算することなく呼び出し値を得られるようにすることです。
都度計算しなくて良くなることからパフォーマンス向上が期待できます。

基本形

依存配列が空の場合

const sampleMemoFunc = () => {
  const memoResult = useMemo(() => hogeMemoFunc(), [])

  return <div>{memoResult}</div>
}

依存配列=[deps] へ空配列を渡すと何にも依存しないので、1回のみ実行。
つまり、依存関係が変わらない場合はキャッシュから値をとってくる。

依存配列に値が入っている場合

props.nameの値が変わったときだけ関数を再実行させたい場合は以下のように書きます。

const sampleMemoFunc = (props) => {
  const memoResult = useMemo(() => hogeMemoFunc(props.name), [prope.name])

  return <div>{memoResult}</div>
}

依存配列=[deps] へ変数を並べると、変数のどれかの値が変わった時にfuncを再実行する。
つまり、依存関係が変わった場合に再実行する。

サンプル

import React, {useMemo, useState} from 'react'

const UseMemo = () => {
  const [count01, setCount01] = useState(0)
  const [count02, setCount02] = useState(0)

  const result01 = () => setCount01(count01 + 1)
  const result02 = () => setCount02(count02 + 1)

  // const square = () => {
  //   let i = 0
  //   while (i < 2) i++
  //   return count02 * count02
  // }

  const square = useMemo(() => {
    let i = 0
    while (i < 200000000000) i++
    return count02 * count02
  }, [count02])

  return (
    <>
      <div>result01: {count01}</div>
      <div>result02: {count02}</div>
      {/* <div>square: {square()}</div> */}
      <div>square: {square}</div>
      <button onClick={result01}>increment</button>
      <button onClick={result02}>increment</button>
    </>
  )
}

export default UseMemo

square関数をuseMemoに代入しない場合

const square = () => {
  let i = 0
  while (i < 200000000000) i++
  return count02 * count02
}

return <div>square: {square()}</div>

square関数をuseMemoに代入しない場合、square関数の処理に関係ないはずのresult01ボタンを押した場合でも明らかに処理が重い。
count01はsquare関数の処理は通していないので関係無いはずだが、コンポーネントが再生成されたタイミングでsquare関数が実行されてしまうことが原因で、処理が重くなっている。

square関数をuseMemoに代入した場合

const square = useMemo(() => {
  let i = 0
  while (i < 200000000000) i++
  return count02 * count02
}, [count02])

return <div>square: {square}</div>

square関数をuseMemoへ代入した場合、result01ボタンを押した時に処理の重さは感じられなくなった。

square関数をuseMemoに代入し値を保持することで、依存配列であるcount02が更新されない限り、square関数の処理が実行されなくなったため、result01ボタンを押した場合の処理が軽くなった。

React.memo/useCallback/useMemo関連の記事を書き直しましたので、よろしければどうぞ!!
- 【React】もっと速くなる!?パフォーマンス最適化に挑戦!

最後に

次回は useRef について書きたいと思います。

参考にさせていただいたサイト
https://reactjs.org/

seira
エイチームライフスタイルのフロントエンドデザイナ。 最近はReact, Rails, php, jQuery Sass, Photoshop, Figmaなどを触っています。
life-a-tm
人生のイベントや日常生活に密着した比較サイト、情報サイト等様々なウェブサービスを企画・開発・運営
https://life.a-tm.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away