はじめに
useStateを使い、前の状態を元に状態を設定する必要がある場合に、通常時のsetItem(〇〇)
とは少し違った書き方にすべきことを知ったのでまとめておく。
結論
前の状態を元に状態を設定する必要がある場合には、setCheck(prevIsOpen => !prevIsOpen);
という書き方を使う必要がある。
詳細
状態の更新は非同期で行われる可能性があります。
Reactは、パフォーマンスのために、複数のsetState()
コールを1回の更新にまとめることがあります。
よって、this.props
とthis.state
は非同期に更新される可能性があるので、次の状態に更新するために元々の値をコードに含めてはいけません。
例えば、以下のコードではカウンターの更新に失敗する可能性があります。
this.setState({
// 新しくsetStateするcounterを計算する際に元々のstateとpropsの値を参照している
counter: this.state.counter + this.props.increment,
});
この問題を解決するには、オブジェクトではなく以下のような関数を受け取る形式のsetState()
を使用します。
// 明示的に、更新前の(state, props)を受け取り、setStateによる更新を行う。
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
HooksのuseStateを用いる場合も同じ用に、書くことができます。
// 何かしらの開閉をisOpenというstateで管理する場合を例にします。
const [isOpen, setIsOpen] = useState(false);
// 更新前のisOpenを受け取り、"!"で反転させる
// 更新前の値であることがわかるように、prev~~とつけても良い
setCheck(prevIsOpen => !prevIsOpen);
おわりに
Hooksの細かい部分ではあるが、setStateが非同期に行われる可能性があることなど、新しい領域のことを学べている実感があった。