よく考えると原理が分らない。
import { useState } from 'react';
function MyCounter()
{
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [count3, setCount3] = useState(0);
return (
<div>
<p>counter1 = {count1}</p>
<button onClick={() => setCount1(count1 + 1)}>1++</button>
<p>counter2 = {count2}</p>
<button onClick={() => setCount2(count2 + 1)}>2++</button>
<p>counter2 = {count3}</p>
<button onClick={() => setCount3(count3 + 1)}>3++</button>
</div>
);
}
ありがちで単純な例ですがcount1, count2, count3 はクロージャでもなく、何らかのオブジェクトでもなく、ポインタ(そもそもJSに無いはず)でもなく、単にnumberのプリミティブ値です。
JavaScriptの言語仕様でこんなこと出来るの? 何かとんでもないトリッキーな方法でも使ってるの? って思ってました。
でも実際はものすごく単純なようで、useState()が呼び出さた順(index)に配列にキャッシュされて、戻り値の二つ目はその要素を変更するクロージャだと考えるとスッキリします。
てっきりこの関数が呼ばれるのはマウント時の1回だけで、戻り値のJSXはその後使いまわされるものだと思ってしまい気付くのに遅れました。
console.log()を張って気づいたんですが再レンダリングの都度呼ばれているんですね、納得。
const cache = [];
function MyCounter()
{
const [count1, setState1] = useState(0); // [ cache[0] || 0, newValue => cache[0] = newValue ]
const [count2, setState2] = useState(0); // [ cache[1] || 0, newValue => cache[1] = newValue ]
const [count3, setState3] = useState(0); // [ cache[2] || 0, newValue => cache[2] = newValue ]
// ...
}
めちゃくちゃ単純に書くとこんな感じ。
cacheが適切かどうかはおいておいてイメージしやすい名前に変えてますが、
https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/
を参考にしました。
実際のコードはどうなってるのか知らないですし、もっと複雑でしょうがモヤモヤは解けたかな。