TekRog
thumbnail

【React】Sliceを用いたReduxの簡単な実装方法

更新日:(作成日: )

カテゴリー:

シェア!

Redux ToolKitで提供されているSliceを用いると、Reduxを使う際、ActionとReducerを1つにまとめて記述できます。また、ステートの更新の際にイミュータブルでない書き方をしても値の更新がされます。そんな何かと便利なSliceの使い方について、最小限の構成でシンプルに紹介します。

Redux ToolKitの準備

Sliceを使うにはRedux ToolKitが必要です。コンソールから追加します。

npm install @reduxjs/toolkit

Sliceファイルの定義

冒頭でも述べましたが、SliceとはReducerとActionを組み合わせたものです。

ステートの例

次の「string型のname」と「number型のage」のステートを更新する処理を考え、Sliceの具体的な使用方法について解説していきます。

interface PersonState { name: string age: number }

初期値を適当に決めます。なお、後から別ファイルで利用するためexportしておきます。

export const initialState: PersonState = { name: 'taro', age: 20 }

このstateに対して2つのactionを定義します。

  • ① ageを+1する
  • ② 名前を入力された値に変える

Sliceの書き方

上記2つの操作に対するSliceは次のように記述します。

const PersonSlice = createSlice({ name: 'person', initialState, reducers: { //リデューサ+アクション incrementAge(state) { state.age++ }, changeName: (state, action: PayloadAction<string>) =>{ state.name = action.payload } } })

nameにこのスライスの名前、
initialStateで初期値を設定し、
reducersでリデューサとアクションを同時に記述しています。

  • 1つめの incrementAgeはageを+1する処理です。
  • 2つめのchangeNameは、nameをdispatchされた値に変更する処理です。

コードのように、第一引数にはstate、第二引数にはactionを指定します。actionはPayloadAction<payloadの型>で型付けしています。

そして、コードのようにイミュータブルな値の操作でstateの更新が可能となっています。これは内部的にImmerという「イミュータブルな操作をミュータブルな操作に変換する」ライブラリを使っているので可能となっています。

最後にこのSliceからリデューサとアクションを切り離します。

//アクションの切り出し export const { incrementAge, changeName } = PersonSlice.actions //リデューサの切り出し export const PersonReducer = PersonSlice.reducer

以上をまとめると、Sliceのファイルは次のようになります。

import { createSlice, PayloadAction } from '@reduxjs/toolkit' interface PersonState { name: string age: number } //初期値 export const initialState: PersonState = { name: 'taro', age: 20 } //スライス const PersonSlice = createSlice({ name: 'person', initialState, reducers: { //リデューサ+アクション incrementAge(state) { state.age++ }, changeName: (state, action: PayloadAction<string>) =>{ state.name = action.payload } } }) //アクションの切り出し export const { incrementAge, changeName } = PersonSlice.actions //リデューサの切り出し export const PersonReducer = PersonSlice.reducer

たったこれだけでReducerとActionに相当する処理の記述が終わりました。

Storeファイル

Redux ToolKitのconfigureStoreを使うと簡単に記述できます。
使用方法を次のコードに示します。

import { configureStore } from "@reduxjs/toolkit" import { initialState as personInitialState, PersonReducer } from "./PersonSlice" export class RootState { person = personInitialState } //リデューサ const reducer = { person: PersonReducer } //ストア const store = configureStore({ reducer }) export default store

Componentファイル

このSliceを利用するコンポーネントの例を記載します。

import { FC, useState } from 'react' import { useSelector, useDispatch } from 'react-redux' import { incrementAge, changeName } from "./PersonSlice" import { RootState } from "./Store" const App: FC = () => { // ストアからstate取得 const person = useSelector((state: RootState) => state.person ) // dispatch const dispatch = useDispatch() //フォームの入力値 const [name, setName] = useState(person.name) //dispatchはJSX内で行っている return ( <> <p>name: {person.name}</p> <p>age: {person.age}</p> {/* incrementAgeのdispatch */} <button onClick={() => dispatch(incrementAge())}>age + 1</button> {/* changeNameのdispatch */} <input value={name} onChange={e => setName(e.target.value)}/> <button onClick={() => dispatch(changeName(name))}>change name</button> </> ) } export default App

まとめ

以上がSliceを使う単純な例になります。このようにとてもシンプルに分かりやすい記述ができます。
実際は他のステートを利用したりより複雑な記述が必要になるかと思いますが、この基本さえ抑えておけば応用が利きます。

より複雑な使い方は、公式ドキュメントを参照下さい。