Redux のセッティングは難しいイメージですが、Redux Tookit を使うと、簡単にグローバルな状態を管理することができます。

手順は、ほとんど公式サイト(https://redux-toolkit.js.org/)を参考にしました。

まずは、React Redux と Redux Toolkit をインストールします。

プロジェクトのターミナルを開き、npm install @reduxjs/toolkit react-reduxを実行します。

src フォルダ内に app フォルダを作成します。

app フォルダ内に store.ts を作成しましょう。

image2

Redux の store を作成します。

Redux Toolkit のconfigureStoreが、store のセットアップを簡素化してくれます。

configureStoreの中には、状態を更新するためのreducerを設定します。

import { configureStore } from "@reduxjs/toolkit"

export const store = configureStore({
  reducer: {},
})

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

次に index.tsx に React Redux のProviderを設定します。

先程作成したstoreもインポートします。

import { store } from "./app/store"
import { Provider } from "react-redux"

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
)

src フォルダ内に、features フォルダを作成します。

features フォルダ内にさらに counter フォルダを作成し、counterSlice.ts を作成します。

image3

counterSlice.ts に初期状態とスライスを識別するための名前、状態を更新する方法を設定します。

今回は、初期状態をvalue: 23、スライスの名前をcounterとします。

状態の更新は、カウンターのように、incrementを実行すると 1 プラス、decrementを実行すると 1 マイナスとします。

import { createSlice, PayloadAction } from "@reduxjs/toolkit"

export interface CounterState {
  value: number
}

const initialState: CounterState = {
  value: 23,
}

export const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    increment: (state: { value: number }) => {
      state.value += 1
    },
    decrement: (state: { value: number }) => {
      state.value -= 1
    },
  },
})

export const { increment, decrement } = counterSlice.actions

export default counterSlice.reducer

初めに作成した、store.ts に移動します。

reducer 内にスライスの名前とスライスの名前に Reducer を付けて指定します。

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
})

App.tsx へ移動します。

React Redux のuseSelectoruseDispatchをインポートします。

また、store.ts からRootStateをインポートします。

さらに、counterSlice.ts からdecrementincrementをインポートします。

import { RootState } from "./app/store"
import { useSelector, useDispatch } from "react-redux"
import { decrement, increment } from "./features/counter/counterSlice"

ストアからデータを読み込むために、useSelectorを設定します。

Redux のactiondispatchするために、useDispatchも設定しましょう。

const age = useSelector((state: RootState) => state.counter.value)
const dispatch = useDispatch()

カウンターボタンを return 内に作成します。

function App() {
  const age = useSelector((state: RootState) => state.counter.value)
  const dispatch = useDispatch()

  return (
    <>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          +
        </button>
        {age}
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          -
        </button>
      </div>
    </>
  )
}

一通り完成したので、ブラウザで確認すると、

image4

初期値である 23 が表示されています。

+ボタンをクリックすると、

image5

数が 1 追加されました。

試しに、別のコンポーネントでも状態が管理できるか、確認してみましょう。

components フォルダ、Age.tsx

import React from "react"
import { RootState } from "../app/store"
import { useSelector } from "react-redux"

const Age = () => {
  const age = useSelector((state: RootState) => state.counter.value)

  return <>{age}歳</>
}

export default Age

App.tsx

<>
  <Age />
  <div>
    <button aria-label="Increment value" onClick={() => dispatch(increment())}>
      +
    </button>
    {age}
    <button aria-label="Decrement value" onClick={() => dispatch(decrement())}>
      -
    </button>
  </div>
</>

ブラウザで確認すると、

image6

Redux で管理している状態が、別コンポーネントでも使用することができました。

ブログ一覧