はじめに
チェックボックスのチェックした値でフィルターをかけようとしたところ、期待値通りのフィルタリングができませんでした。備忘録として解決方法をまとめます。
問題
チェックボックスをチェックした時にフィルタリングできるようしたいが、チェックを外したときにフィルタリングが適用されてしまう。
原因
チェック時の値をuseStateでセットする前に、データ取得処理が実行されていた。
setGenreIdで値を更新する際、即座に反映されず、関数(handleChange)実行後に反映されます。
公式ドキュメントより引用
set 関数の呼び出しは、実行中のコードの state を変化させません。
// チェックボックスの状態管理
const [genreId, setGenreId] = useState<string[]>([]);
// チェックボックスの変更ハンドラー
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.checked) {
setGenreId([...genreId, e.target.value]);
} else {
setGenreId(genreId.filter((id) => id !== e.target.value));
}
const searchByGenresData = await getDataByGenres(genreId); //←setGenreIdの値は更新されていない、古い値を設定している
setData(searchByGenresData);
};
解決方法
1. useEffectを使用する
- const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.checked) {
setGenreId([...genreId, e.target.value]);
} else {
setGenreId(genreId.filter((id) => id !== e.target.value));
}
- const searchByGenresData = await getDataByGenres(genreId);
- setData(searchByGenresData);
};
+ useEffect(() => {
+ const fetchDataByGenres = async () => {
+ const searchByGenresData = await getDataByGenres(genreId);
+ setData(searchByGenresData);
+ };
+ fetchDataByGenres();
+ }, [genreId]);
2. 新しい変数で格納する
公式ドキュメントより引用
次の state が必要な場合は、set 関数に渡す前に一度変数に保存することができます。
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
+ let newGenreId: string[];
if (e.target.checked) {
- setGenreId([...genreId, e.target.value]);
+ newGenreId = [...genreId, e.target.value];
+ setGenreId(newGenreId);
} else {
- setGenreId(genreId.filter((id) => id !== e.target.value));
+ newGenreId = genreId.filter((id) => id !== e.target.value);
+ setGenreId(newGenreId);
}
- const searchByGenresData = await getDataByGenres(genreId);
+ const searchByGenresData = await getDataByGenres(newGenreId);
setData(searchByGenresData);
};
おわりに
Stateの管理、難しいです。使いこなせるようになりたいです。
参考