React を使い始めてからずっと扱いづらいと思ってる部分の一つが state のリセット
コンポーネント内なら難しくないけど 外から受け取るデータに応じてのリセットがあまり考慮されてない気がする
そういう使い方を推奨してないんだろうけど やっぱりそういうことしたいときは結構出てくる

特に コンポーネント内の途中の状態を変更のたびに親に伝えるのは無駄だし 親の処理が増えてくる
ページのコンポーネントになってくると 子孫コンポーネントの状態更新の処理があれこれ混ざって複雑になってる
やっぱり理想はコンポーネントの中での操作が完了してから初めて親に伝えるもの
外から受け取ったデータを state に保持して 完了時に onXXX などで受け取った関数を呼び出すだけだからこれは普通にできる
問題なのは 2 回目以降
state は引き継がれるから前回の情報がコンポーネントに残ったまま

外から受け取るデータが変更されたタイミングで state をリセットしたいので こういう方法で対処してた

const Component = ({ value }) => {
const [state, setState] = useState(value)

useEffect(() => {
setState(value)
}, [value])

return (
...
)
}

これの欠点は 変更時に 1 回ムダにレンダリング処理が行われること
それと useState が多いと setState みたいな関数を何度も呼び出さないといけないところ
コンポーネント内でリセット機能があってすでに関数を用意してるならそれを呼び出せばいいけど
あと useEffect のこういう使い方って正しいの?と思うところもある

その他の方法は key を使うこと
親コンポーネントが props を変えるときに key も変えればリセットできる
でもこれはコンポーネントを使う側に 追加でしてもらうことが増えてあまり良い方法じゃないと思う
key の変え忘れでバグになることが多そう

それで思ったのがコンポーネントを 2 重にして key の制御もコンポーネント側でやる方法

const ComponentInternal = ({ value }) => {
const [state, setState] = useState(value)

return (
...
)
}

const Component = (props) => {
const key = useMemo(() => Math.random(), [props.value])
return <ComponentInternal key={key} {...props} />
}

結構いい感じ
useMemo を使って Math.random() を返すことで依存プロパティが変わったときに key を変えることができる
変わったときにコンポーネントをリセットしたいプロパティを useMemo の依存プロパティに設定する

都度書くのも面倒なのでもう少し楽に作れるように

const resetStateComponent = (Component, deps) => (props) => {
const key = useMemo(() => Math.random(), deps.map(d => props[d]))
return <Component key={key} {...props} />
}

を用意しておいて 作るときは元にするコンポーネントと依存プロパティの名前の配列を引数で渡す

const Component = resetStateComponent(ComponentInternal, ["value"])

key を変える以上 コンポーネント全体を作り直すので リスナをつけていて一瞬でも解除したくないとか API の fetch をしていてリセットのタイミングで毎回 fetch したくないとかあるなら 外側コンポーネントを自作してリセットしたくないデータはそっちで準備して props で渡すか key を使わず state リセットする方法にしたほうが良さそう