Wowgineer Notes

WowTechエンジニアの徒然開発日記

Wowgineer Notes

〜新たな"Wow"を生み出す〜

Redux Toolkit を導入してみたら、とても良かった!!!

Web開発チームの山本です。

Reactで作成した既存のアプリケーションにRedux Toolkitを導入してみたのですが、想像以上によかったので、今回はRedux Toolkitについて紹介します。

 

Redux Toolkit とは

Reduxを効率的に開発するために作られた公式のツールセットです。 Reduxの公式ドキュメントにもRedux Toolkitについて書かれています。Reduxの公式ドキュメントでも、Redux Toolkitを使うことを推奨しており、Reduxをこれから始める人やシンプルにRedux書きたい人にも良さそうです。Redux Toolkitには、Immer、Reselect、Redux-Thunkも含まれているので、自分でインストールする必要がないので、助かります。

 

インストール

既存のアプリケーションにReduxを導入するときは、Redux ToolkitとReact Reduxをインストールしましょう。React Reduxは、Redux用の公式React UIバインディングレイヤーです。Redux自体はどんなフレームワークとも一緒に使用することができるので、ReduxとReactを一緒に使う場合は、React Reduxも使ってこの2つのライブラリを結びつける必要があります。詳しくはこちら

npm install @reduxjs/toolkit react-redux

 

Redux Toolkitを使う前は、Middlewareとしてredux-loggerを入れてStoreの更新のログをコンソールに表示していたのですが、ChormeのデベロッパーツールにReduxの拡張機能が使えるようになったので、redux-loggerは入れなくてもいいと思います。Reduxの拡張機能でStoreのデータを確認できたり、アクションの呼び出しも追跡できます。

 

ReducerとActionを一緒に書ける

下記はRedux Toolkitで使用されているAPIです。これまでは、ActionとReducerを別のファイルで書いたのが、Redux Toolkitではシンプルにかけるようになったので、同じファイル内で管理できるようになりました。

 

これまでReduxでアクションを定義する時は、アクションタイプの定数と、そのタイプのアクションを構築するためのアクションクリエーター関数を別々に宣言していました。Reduxのreducerは、switch文を使って実装されることが多く、扱われるアクションタイプごとに1つのケースが必要です。

Action


const RECEIVE_All_TEMPLATE_DATA = 'RECEIVE_All_TEMPLATE_DATA' function set_all_template_data(data) { return { type: RECEIVE_All_TEMPLATE_DATA, payload:data, } }

Reducer

const initialState = {templates: [] }

function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'RECEIVE_All_TEMPLATE_DATA':
      return { ...state, templates: [ ...action.data]}
    default:
      return state
  }
}

Redux ToolkitのcreateActionとcreateReducerを使うと、上記のコードをシンプルに書くことができます。

import {  createAction, createReducer } from '@reduxjs/toolkit';


const setAllTemplates = createAction("RECEIVE_All_TEMPLATE_DATA"); const initialState = { templateArray:[] } const templateReducer = createReducer(initialState, (builder) => { builder .addCase(setAllTemplates, (state, action) => { state.templateArray = action.payload }) });

 

またcreateSliceを使うと、Actionと Reducerも一緒に書くことができます。アクションタイプの定数やswitch文がなくなり、かなりコード自体も見やすくなり、コード量も少なくなったので、嬉しいです。actionのpayloadの値をカスタマイズしたい時は、createSliceではprepareを使えばできるので、私は基本的にcreateSliceを使っています。

import { createSlice } from '@reduxjs/toolkit';

const initialState = {
templateArray:[]
}

const templateSlice = createSlice({ name: 'templates', initialState: initialState, reducers: { setAllTemplates: (state, action) => { state.templateArray = action.payload } } })

 

 TypeScriptに対応している

Redux Toolkitのドキュメントに、TypeScriptでの使い方も書かれているので、TSを使用している既存サービスにRedux Toolkitを導入してもサンプルコードも豊富なため、特に大きなハードルはありませんでした。

 

Storeの設定やHooksの設定もサクッとできました。

app/store.ts

import { configureStore } from '@reduxjs/toolkit'
import reducer from '../reducers'

export const store = configureStore({
  reducer
})

export type RootState = ReturnType<typeof store.getState>

export type AppDispatch = typeof store.dispatch

app/hooks.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'

// 元からあるuseDispatchやuseSelectorの代わりに、アプリ全体で使用します
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

 

ただ、createAsyncThunkで結構ハマってしまいました。3つのパラメーターの型定義が、複雑で最初は混乱しました。この方のブログ記事に詳しく書かれており、とても助かりました。ありがとうございます。createAsyncThunkは、非同期リクエストにおける各ライフサイクル毎(非同期処理中、非同期処理の成功時、非同期処理の失敗時)に処理をフックすることができるので、便利です。

 

まとめ

以前は、複数のファイルをまたがってReduxの設定をしていたのですが、Redux Toolkitによって、かなりシンプルに書けるようになったので嬉しいです。拡張機能もまだ触りきれていない部分もあるので、引き続き色々と試していきたいです。

 

 

我々ワウテック技術開発部はこのような環境で開発をしています。
興味を持った方がいらっしゃればいつでもご連絡下さい。

f:id:wowtech-dev:20190313163146j:plain