◆ ローカルステートがあると前回との差分を検出する処理があちこちに必要になる
◆ 別のところのローカルステートを更新できないので props や hook の値を見て更新することになる
◆ グローバルステートだとまとめて更新できるのでそういう問題がない
◆ だけど React のコンポーネントの考え方やライブラリのフックを考えると向いてない

不満点

React を使っていて困る部分や不満に感じる部分って 前回のレンダリング時の値を知る必要があるところが多いと思いました
過去の state と比較して こういう風に変わった場合は◯◯するという場合 ref に過去の state を保持して useEffect で ref を更新するような手段を取ることになります
過去の state そのものを知りたいことはそんなに多くないですが 変わったことを検知したいことは結構多いです
props や hook で得られる値が変わったら state をリセットしたいとかです

こういうコードが多いと 処理が複雑化したり コードの見通しが悪くなったりします
そもそも useEffect を副作用とは違うようなところで 変更検出のために使うのはやっぱりなにか違うと思いますし

React 側でいい感じにこういうケースを扱う仕組みがあればいいのにと思うのですがないのですよね
やっぱり React って今の状態を表すデータから DOM を作るというものなので 前回の状態を知る必要があるというのが React にあってないんじゃないかと思います
そうは言っても実際にはそういうケースが多いのですよね

state に過去 state を持たせる

思いついたのは 前回の状態も必要というなら 今の状態の一部として前回の情報を持つということです

setState(state => {
// すべての履歴をもたないように prev.prev は消す
const prev_state = { ...state, prev_state: null }
const new_value = state.value + 1
return { ...state, value: new_value, prev_state }
})

state の更新時に state のプロパティのひとつとして前回の state を残すことで state だけで今と前の状態を参照できます
state.prev_state で前の state にアクセスできます

ただ これにしたところでほとんどの場合は 差分情報を DOM に反映するのではなく state の更新や onXXX 関数の呼び出しに使います
結局 useEffect を使うのであまり改善した気がしません
むしろ state の更新が面倒になった気がします

グローバルステート

差分を使って何をするかを考えてみると ほとんどはどこかの state の更新です
state を更新するなら 再レンダリングの原因になった state の更新で一緒に行うのが理想です
しかし ローカルステートがあちこちのコンポーネントにあるのでそれは難しいです

子コンポーネントで state を持っている場合は props を更新して渡して 子コンポーネント内で差分を検出して更新になります
key を変えることもできますが コンポーネントの再マウントになるので 他の state もクリアされたり useEffect の呼び出しなど余計な処理も多くなります
コンポーネント内でも カスタムフックの中で state が管理されているので フックの返り値として受け取った値が変わっているかを検出するしかないこともあります

こういうのって React のコンポーネントの中で state を保持するのが原因だと思います
フックは便利ではありますが React の外でやるべきものも React の中に持ち込んでしまうのがデメリットですね

実際 引数で受け取る state から DOM 定義を返すだけの純粋関数で成り立っていて コンポーネントという概念を持たないライブラリだとこの問題はないですし
ただ Context のような機能がなかったり別の不便なところはありますけど

コンポーネントがあっても グローバルステート 1 箇所で管理すれば 必要な箇所は全てまとめて変更できますし コンポーネントは引数から DOM 定義を返すだけになってシンプルです
React ではないですが グローバルステートで作ったものでは コンポーネント側は画面表示をどうするかだけに集中できてよかったです

ただ React はコンポーネント単位で再レンダリングを行い コンポーネントに分けることで再レンダリングを減らすというライブラリです
グローバルステートの更新のたびにトップレベルの再レンダリングというのは向いていませんし パフォーマンスも問題になりそうです
React でグローバルステートなら 最近は見なくなった Redux がありますが そこまで使いやすそうにも思えなかったです
どちらかというと複雑度が増す印象があります

あとグローバルステートにする場合 コンポーネント内でデータを処理しないので データのフォーマットなどコンポーネント用の特別な処理があれば グローバルステートの更新処理の方でそれを呼び出す必要があって コンポーネントにまとまらないです
そういうのがあるので使い回しはコンポーネントよりやりづらいと思います
私の場合は別アプリならそのまま使い回すことはほぼないということでアプリ固有のものとして気にせず直接書いてたりしますけど

グローバルステートの方が良さそうかなと思ったけど React にはあってないのと フックを使うライブラリがある以上どうしようもないので諦めて 差分検出して色々やることにします

const Component = (props) => {
const foo = useFoo()

useDiff((prev, current) => {
//
}, [props.value, foo])

return <div>...</div>
}

const useDiff = (fn, targets) => {
const ref = useRef()

useEffect(() => {
const prev = ref.current
ref.current = targets
fn(prev, targets)
}, targets)
}

そのまま useEffect でもいいですが ぱっと見で目的がわからないと読みづらいので useDiff にしてます
これでもコンポーネントによっては useDiff がいっぱい並んだりで 何したいのかが分かりづらいんですよね