3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【React】useReducer をもっと自由に活用しよう

Last updated at Posted at 2020-01-19

useReducer をもっと自由に

皆さん、useReducer は活用していますか?
useState で十分と思っている場合でも useReducer に置き換えることで、コードがシンプルかつ、わかりやすくなります。

そのためには、Reduxの呪縛を解き払ってください。useReducerに Action type は必要ないですし、Flux Standard Action も必要ありません。また、今回はdispatchdispatchらしい使い方はしていません。
つまり、Redux と同じ使い方をする必要はありません。

🙅‍♀️別にActionType必須ではない
const [state, dispatch] = useReducer((state, action) => {
  switch(action.type) {
    case 'FOO_ACTION':
      return { ...state, foo: action.foo }
    case 'BAR_ACTION':
...

useReducer 活用例

では、useReducer を使用すると、どのように変わるのでしょうか。簡単なサンプルコードをもとに紹介します。
【追記】下記の例は、Reactではうまく動作しません1(preactでは動作します)。後日差し替え予定ですが、イメージのつかみやすさから一旦この例のまま紹介します。

例)テキストフィールド
const { value, onChange } = useInput()

return (
  <input type="text" value={value} onChange={onChange} />
)

上記はなんの変哲もないテキストフィールドです。
これに合うカスタム Hooks (useInput) を、useStateuseReducer でそれぞれ作成します。

useState の場合

useStateを使用した場合
export const useInput = () => {
  const [value, setValue] = useState('')

  const onChange = useCallback((event) => {
    setValue(event.currentTarget.value)
  }, [])

  return { value, onChange }
}

useState を使用した場合、Hooks は2つ使用します。今回の用途では useCallback はオーバーキル感がありますが、他コンポーネントや他 Hooks で使用する可能性がありますので、メモ化しておくのが良いでしょう。
いずれにしても、onChange 関数を作成するには setValue をラップします。

useReducer の場合

useReducerを使用した場合
const inputAction = (state, event) =>
  event.currentTarget.value

export const useInput = () => {
  const [value, onChange] = useReducer(inputAction, '')

  return { value, onChange }
}

useState を使用した場合よりも、シンプルになりました。
useReducer で記述するメリットは下記の2つです。

  • 状態とそれを更新する関数が、ワンセットになる
  • reducer 部分は純粋関数であり、Hooks やコンポーネントの外に出せる

1つ目について、setValue のような中間の Setter が生まれませんし、用途に合わせる関数(onChange)を別途作る必要もありません。
また、2つ目の関数外部化は、テストがしやすくなるだけでなく、無駄なオブジェクトを生成しないというパフォーマンス面のメリットもあります。

まとめ

useReducer を使用する場合、Redux 等の使い方に縛られる必要はありません。
単純な state でも useReducer に置き換えることで、コードがシンプルかつ、わかりやすくなり、テスタビリティがあがってパフォーマンスも上がります!

  1. React では、DOM の Event を独自オブジェクト(SyntheticEvent)で wrap しているのですが、それの有効期限が useReducer の処理実行タイミングまで生きていないのが原因です。

3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?