React の useState をいろいろいじってるときに微妙にハマったのでメモ。
useState を複数使って state を定義しているときに、それらが相互依存しているとき期待通りに動かなかった。
なので、相互依存しているものは同じ state に入れることで解消しました。
サンプル
loading
が true
のとき、 submit
できないようにしたいとする。
(loading === true
のとき、 canSubmit === false
にしたい)
import React, { FC, useState, useEffect } from 'react';
const StateDependOnEachOther: FC = () => {
// 別々の state に定義したバージョン
const [canSubmit, setCanSubmit] = useState(true);
const [loading, setLoading] = useState(false);
// loading の状態に合わせて canSubmit を変える
const submitting = () => {
setCanSubmit(() => {
if (loading) {
return false;
}
return true;
});
};
// 同じ state に定義したバージョン
const [state, setState] = useState({
canSubmit2: true,
loading2: false,
});
// loading の状態に合わせて canSubmit を変える
const submitting2 = () => {
setState(prevCanSubmit2 => {
if (prevCanSubmit2.loading2) {
return {
...prevCanSubmit2,
canSubmit2: false,
};
}
return {
...prevCanSubmit2,
canSubmit2: true,
};
});
};
useEffect(() => {
// loading を true に変更
setLoading(true);
setState(prevState => {
return { ...prevState, loading2: true };
});
// loading === true のとき、 canSumit は false にしたい
submitting();
submitting2();
// eslint-disable-next-line
}, []);
return (
<>
<div>別々の useState で定義: canSubmit: {`${canSubmit}`}</div>
<div>同じ useState で定義 state.canSubmit2: {`${state.canSubmit2}`}</div>
</>
);
};
export default StateDependOnEachOther;
結果
- 別々の useState で定義した場合は loading の変更が反映されず、 canSubmit は true のまま
- 同じ useState 定義した場合は loading の変更が反映され、 canSubmit は false になる
実際に動かしたものがこちら
とりあえず useState に定義すればいいと思ってたけど、関連するものはまとめる、または1コンポーネントの中で useState は一つにして、必要なものは全部その中に突っ込む方が良さそう。