propsが変化したときにstateをリセットする
propsが変化した時に、useStateのstateをどうやってresetするか
こういう使い方をするhooks useSelectItemを定義したい
コード
https://gyazo.com/ca0c52bff283f5f20190c7cddb6092a7
リストがあって、aとかbとかをクリックするとそれだけfilterするものを考える
Bad1
普通にこう書くと、切り替えた時に落ちる
code:ts
const useSelectItem = (
entries: NonEmptyList<User>
) => {
const index, setIndex = useState(0);
return {
setIndex,
selectedItem: entriesindex
};
};
https://gyazo.com/2247195e0ad91d69e50e09a73d632bb6
aで絞ると要素は3つの配列なのに、indexが4を指したままなため
Bad2
useEffectを使う
コレは何の解決にもなっていない
この例よりももっとシビアな例
code:ts
const useSelectItem = (items: Entity[]) => {
const index, setIndex = useState(0);
// この3行を追加
useEffect(() => {
setIndex(0);
}, items);
const next = useCallback(() => {
setIndex((index + 1) % items.length);
}, index, items.length);
console.log({ index });
return {
next,
selectedItem: itemsindex,
};
};
useEffectは、
①rendering後に、
②depsの変更を検知したら、再renderingする
今回の例だと、①が起きた時点で境界値の外にアクセスしているので手遅れ
また、Componentの構造上、この節のkeyを使った解決策は使えない
これで動く
code:ts
const useSelectItem = (items: Entity[]) => {
const prevItems, setPrevItems = useState(items);
const index, setIndex = useState(0);
if (prevItems !== items) {
setPrevItems(items);
setIndex(0);
}
const next = useCallback(() => {
setIndex((index + 1) % items.length);
}, index, items.length);
console.log({ index });
return {
next,
selectedItem: itemsindex > items.length - 1 ? 0 : index,
};
};
これでちゃんと動くけど、本当に正しい解決策なのか?mrsekut.icon
やりたいことに対して複雑すぎる気もするが
参考
そのエフェクトは不要かも – React