概要
配列の中身の変化だけでは反応してくれない。
→新しい配列としてset○○に入れる必要がある。
配列をスプレッド構文で入れ直してあげればok。
想定例
たとえばカテゴリ選択ボタンみたいに、複数ボタンがあって、どのボタンがactivate中かをすべてのボタンについて管理するという場合。
ボタンごとにuseStateを使ってもいいが、コードの長さや拡張性の観点から、すべてのボタンの状態を1つの配列で管理してしまった方が楽。
const [isAvtivates, setIsActivates] = useState(Array(buttons.length).fill(true))
のような想定。
失敗例
const onPressButton = (idx: number): void => {
isActivates[idx] = !isActivates[idx];
setIsActivates(isActivates);
};
これがなぜだめかというと、isActivatesの中身に変更はあるが、isActivatesという配列自体は変わっていないからです。
useStateは配列やオブジェクトの中身の変化までは見てくれず、この書き方だと変化したことに気づいてくれないからだそう。
(詳しい話はこちら:https://ja.reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update)
オブジェクトの場合の対応はこちらの記事が参考になります。
正解
const onPressButton = (idx: number): void => {
isActivates[idx] = !isActivates[idx];
setIsActivates([...isActivates]);
};
スプレッドしてしまえば新しい配列に変わるので、実はこの違いだけで解決できる。