🦔

React useMemoの内部実装を読んでみました

2022/11/09に公開

サンプルコード

import { useMemo, useState } from 'react';

const App = () => {
    const [dataInvolved, setDataInvolved] = useState(1)
    const [dataNotInvolved, setDataNotInvolved] = useState(1)

    const nums = useMemo(() => dataInvolved * dataInvolved, [dataInvolved])
    const handleClick = () => {
        setDataInvolved(d => d + 1)
    }

    const handleClick2 = () => {
        setDataNotInvolved(d => d + 1)
    }

   return (
       <div className='container'>
        <button onClick={handleClick}>click</button>
        <button onClick={handleClick2}>click2</button>
        <p>count:{nums}</p>
       </div>
   );
};
export default App

動作

  • clickをクリックしたとき、countが変動します
  • click2をクリックしたとき、countが変動しません

メモリ図

https://viewer.diagrams.net/?tags={}&highlight=0000ff&edit=_blank&layers=1&nav=1&page-id=4uyOpDTRfktK-BIeQtTz&title=useMemo.drawio#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D1aEf64Maa2jyRdkZZw7fqB268DMwYU-4I%26export%3Ddownload

内部実装

mount時

  1. Appを実行します
  2. useMemoを実行します

https://github.com/facebook/react/blob/1e3e30dae2bcfbeb0abc686f2a37aec208eedb39/packages/react/src/ReactHooks.js#L153-L159

  1. mountMemoを実行します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2193-L2205

  1. hookオブジェクトを生成します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2197

  1. callbackを実行します

https://github.com/facebook/react/blob/1e3e30dae2bcfbeb0abc686f2a37aec208eedb39/packages/react-reconciler/src/ReactFiberHooks.new.js#L2202

  1. callbackの実行結果と今回のdepsをmemoします

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2203

  1. callbackの実行結果をAppにreturnします

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2204

関連stateのアップデート時

  1. Appを実行します
  2. useMemoを実行します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L3213

  1. updateMemoを実行します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2207

  1. memoした値を取り出します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2213

  1. 今回のdepsとmemoしたdepsを比較します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2218

6-1. 5の結果はfalseの場合、callbackを実行して、新しい値とdepsをmemoし、返します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2219

6-2. 5の結果がtrueの場合、memoした値を返します

https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberHooks.new.js#L2219

説明動画

https://www.youtube.com/watch?v=vom72aoD1ek

Discussion