はじめに
カスタムフックを使うことで、ステートの管理を簡潔にし、さらに再利用性の高い実装をすることができます。
また、コンポーネントの関心を少なくし見通しの良いコードになります。
今回はuseReducer
を使用する例を紹介します。
わかりやすいように、3つの実装を順番に説明します。
useState
を使用する例useReducer
を使用する例useReducer
を使用し、カスタムフックにする例
やりたいこと
以下のようなフォームがあるとします。
フォームの<input />
4つに入力される値をステートで管理します。
export default function App() {
return (
<div>
<input
name="lastName"
/>
<input
name="firstName"
/>
<input
name="zipCode"
/>
<input
name="address"
/>
</div>
);
}
1. useStateを使用する例
同じような表現が繰り返し現れているように見えます。
`useState`を使用する例
export default function App() {
const [lastName, setLastName] = useState("");
const [firstName, setFirstName] = useState("");
const [zipCode, setZipcode] = useState("");
const [address, setAddress] = useState("");
return (
<div>
<input
name="lastName"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
<input
name="firstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<input
name="zipCode"
value={zipCode}
onChange={(e) => setZipcode(e.target.value)}
/>
<input
name="address"
value={address}
onChange={(e) => setAddress(e.target.value)}
/>
</div>
);
}
2. useReducerを使用する例
- ステートはオブジェクトになり、見やすくなりました(感じ方には個人差あり)
onChange
のコールバックは、handleChange()
に共通化できました- でも、ちょっと複雑に見えるかもしれない
`useReducer`を使用する例
const initialState = {
lastName: "",
firstName: "",
zipCode: "",
address: ""
};
export default function App() {
const formReducer = (state, { name, value }) => ({ ...state, [name]: value });
const [formState, formDispatch] = useReducer(formReducer, initialState);
const handleChange = ({ target: { name, value } }) => formDispatch({ name, value });
return (
<div>
<input
name="lastName"
value={formState.lastName}
onChange={handleChange}
/>
<input
name="firstName"
value={formState.firstName}
onChange={handleChange}
/>
<input
name="zipCode"
value={formState.zipCode}
onChange={handleChange}
/>
<input
name="address"
value={formState.address}
onChange={handleChange}
/>
</div>
);
}
3. useReducerを使用し、カスタムフックにする例
Hooks
は別ファイル(useForm.js
とします)に切り出し、再利用することができます。
先ほどの例と同じロジックですが、initialState
を引数にとり、
- ステート(
formState
) - ステートを更新する関数(
handleChange
)
を返します。
useForm.js
import { useReducer } from "react";
const useForm = (initialState = {}) => {
// [2.]と同じロジック
const formReducer = (state, { name, value }) => ({ ...state, [name]: value });
const [formState, formDispatch] = useReducer(formReducer, initialState);
const handleChange = ({ target: { name, value } }) => formDispatch({ name, value });
// 追加
return [formState, handleChange];
};
export default useForm;
🐢
コンポーネントの関心は、initialState
だけになりました。
管理するステートが変わったとしても、簡単にフォームの追加や削除を行うことができます。
App.js
const initialState = {
lastName: "",
firstName: "",
zipCode: "",
address: ""
};
export default function App() {
const [formState, handleChange] = useForm(initialState);
return (
<div>
<input
name="lastName"
value={formState.lastName}
onChange={handleChange}
/>
<input
name="firstName"
...以下略
/>
</div>
);
}
まとめ
useReducer
を使うことで、冗長なuseState
の宣言を簡略化し、処理を共通化できる- カスタムフックにすることで、コンポーネントから関心を取り除くことができる