🙌

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

2022/11/07に公開

サンプルコード

import { useReducer } from 'react';

const reducer = (state, action) => {
    switch (action.type) {
        case 'plus':
            return {...state, count: state.count + action.value}
        default:
            return state
    }
}

const App = () => {
    const [data, setData] = useReducer(reducer, {
        count: 1
    })

    const handleClick = () => {
        setData({type:"plus", value: 1})
    }

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

メインステップ

マウント段階

  1. App 関数Componentを実行します
  2. App 関数Componentを実行時にuseReducerを実行します
  3. App 関数ComponentとのFiberNodeのhookを生成します

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L972

  1. dispatch functionを生成します

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L988

  1. 最初stateとdispatch関数を返します

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L993

クリック後の挙動

  1. dispatch関数を読んでApp 関数ComponentのFiberNodeのhookにactionを含めたupdateオブジェクトを入れます

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L2507-L2516

  1. 再レンダリングを走ります

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L2521

再レンダリングの挙動

  1. App 関数Componentを実行します
  2. App 関数Componentを実行時にuseReducerを実行します
  3. App 関数コンポねーとのFiberNodeのhookを新しく生成します
  4. reducer関数を実行して、最新のstateオブジェクトを生成します

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L1118

  1. 新しく生成したhookオブジェクトのプロパティを更新します

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L1136-L1138

  1. 新しいstateオブジェクトとdispatch関数を返します

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L1150

useStateとの違い

useStateとの一番大きなちがいはreducerを自分でカスタマイズできることでうs

useStateはこのreducerを使っていることです

https://github.com/facebook/react/blob/4bd245e9ee22458bcd5b68524c47eaaab2cf2058/packages/react-reconciler/src/ReactFiberHooks.new.js#L962-L965

useReducerは自分で定義できます、サンプルコードでのreducerはいかです

const reducer = (state, action) => {
    switch (action.type) {
        case 'plus':
            return {...state, count: state.count + action.value}
        default:
            return state
    }
}

説明動画

  1. mount stage

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

  1. update stage

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

Discussion