🌊

React useState内部実装を読んでみました(dispatchSetState)

2022/11/02に公開

サンプルコード

import { useState } from "react";

function App() {
  const [count, setCount] = useState(0)

  const handleClick = () => {
    setCount(count + 1)
  }

  const handleClick2 = () => {
    setCount(c => c + 1)
  }

  return (
    <div className='container'>
      <button onClick={handleClick}>click</button>
      <button onClick={handleClick2}>click2</button>
      <p className='subContainer'>{count}</p>
    </div>
  );
}

export default App;

要するには、buttonをクリックしたら、setCountが走ります、stateの変化がview側に表現させるという例です。
では、Reactはどうやってこれを実現したのか見てみました。

結論

setCountを実行した後以下の処理が行いました。

  1. actionをキューに入れます
  2. Reactは全体を再レンダリングを促します
  3. キューにあるactionを消化します。

説明

1. actionをキューに入れま

ここのactionは
action + 1 というpremitive型
もしくは
c => c + 1 という関数型

どっちでもキューに入れられます、違うのは、3の消化する時に、関数というactionなら、実行されます。

queueの場所は以下です
function ComponentのFiberNode-> memorizedState -> queue -> pending

2.Reactは全体を再レンダリングを促します

Reactはactionをチェックします、メモしているstateとのアドレスが違う場合は、Schedulerで再レンダリングを走らせます

3. キューにあるactionを消化します。


関数をレンダリングする時に、useState関数を実行させ、キューにあるactionを全部とって、逐次に消化します。
消化した結果をもって、queue.lastRenderedStateを更新します。
そして、queue.pendingをnullにして、キューをクリアします。

説明動画

actionをキューにいれます。

https://www.youtube.com/watch?v=jV0PY3bwxcY&t=51s

actionを消化する

https://www.youtube.com/watch?v=iTxcKGWm0Gw&t=312s

actionは関数の場合は

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

初期マウント後、dispatchとhookの存在ステータス

https://www.youtube.com/watch?v=fyoj9huioek&t=783s

Discussion