DEV Community

kaede
kaede

Posted on • Edited on

React Redux Tutorial Part 1 -- react-redux の導入 と reduxjs/toolkit の createSlice を使った counter アプリの作成

why

  • 次のプロジェクトで必要とされるから。
  • 以前のプロジェクトで携わったが、reducer や useSelector などを理解できてないままなんとなくで使ってしまっていたから。
  • カスタムフックを作れるようになりたいから。

何をやるのか

https://react-redux.js.org/tutorials/quick-start

React-Redux の公式チュートリアル、クイックスタート

React アプリに redux toolkit の slice を導入して
グローバルステートの count の値をボタンで上下させるプロジェクトを作る。

プロジェクト作成とライブラリのインストール

npx create-react-app redux
Enter fullscreen mode Exit fullscreen mode

これで React のプロジェクトディレクトリを作成

https://react-redux.js.org/tutorials/quick-start

この react-redux 公式チュートリアル通りに

npm install @reduxjs/toolkit react-redux
Enter fullscreen mode Exit fullscreen mode

redux のツールキットと react-redux
これらの npm ライブラリをインストールする


app/store に store ファイルの作成する

https://react-redux.js.org/tutorials/quick-start#create-a-redux-store

この react-redux 公式チュートリアル通りに

src/app/store.js

にストアファイルを作ってみる

import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: {},
})
Enter fullscreen mode Exit fullscreen mode

toolkit のライブラリから configureStore というものをインポートする

configureStore の名前で export する。
中身の reducer はまだない。

普通の redux の combine のようなものだと推測する。


index.js で store ファイルをインポートして Provider に繋げる。

import store from './app/store'
import { Provider } from 'react-redux'
Enter fullscreen mode Exit fullscreen mode

store ファイルをインポートして
react-redux のライブラリから Provider をインポートする

  <React.StrictMode>
    <App />
  </React.StrictMode>
Enter fullscreen mode Exit fullscreen mode

デフォルトでは StrictMode で App が括られているが

  <Provider store={store}>
    <App />
  </Provider>
Enter fullscreen mode Exit fullscreen mode

今回は Provider で括るようにする。


npm start で起動する

Image description

この store と Provider を入れた React アプリを起動すると普通に動く。

redux.js:426 Store does not have a valid reducer. 
Make sure the argument passed to combineReducers is 
an object whose values are reducers.
warning @ redux.js:426
Enter fullscreen mode Exit fullscreen mode

reducer 何もないぞって警告がコンソールに出ている。


features/counter/counterSlice に redux state と reducer がまとまった slice ファイルを作る

https://react-redux.js.org/tutorials/quick-start#create-a-redux-state-slice

src/ に features/counter/ というフォルダを作り

counterSlice.js というファイルを作る

import { createSlice } from '@reduxjs/toolkit'
Enter fullscreen mode Exit fullscreen mode

redux toolkit から createSlice というライブラリをインポートして

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) => {
      state.value += 1
    },
    decrement: (state) => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    },
  },
})
Enter fullscreen mode Exit fullscreen mode

createSlice を使って counterSlice というコンポーネントを作る
公式では export しているが、これを直接外部ファイルで使うことはない
なので export は必要ない。

中に名前、初期値、reducers を作る。
名前には counter, 初期値には 0 を入れて

reducers には increment, decrement, incrementByAmount を作る
increment は state を受け取って中の value を +1 するだけ
decrement は -1 同様にするだけ
incrementByAmount は state だけでなく action も受け取る。
そして state の中の value に action のなかの payload を加算する。

export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer
Enter fullscreen mode Exit fullscreen mode

そしてこれらの reducers 一つ一つに counterSlice の actions を入れる。これがないと

export 'increment' (imported as 'increment') was not found in './counterSlice' (possible exports: counterSlice, default

counterSlice から increment, decrement が読み取れないので必須。

これで counterSlice という state の value を変化させる slice
その中の increment, decrement, incrementByAmount, の reducer
これらが export できた。


app/store で counterSlice から counterReducer を読み込む

このままでは React に導入した Store と、先ほど作った Slice が接続されていない。なので結びつける。

最初に書いた app/store.js に

import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

export default configureStore({
  reducer: {
    counter: counterReducer,
  },
})
Enter fullscreen mode Exit fullscreen mode

先ほど作った counterSlice をインポートして
空だった reducer の欄に coutnerSlicer を追加する。

これで store を redux が空で導入した時に出た

redux.js:426 Store does not have a valid reducer. 
Make sure the argument passed to combineReducers is 
an object whose values are reducers.
warning @ redux.js:426
Enter fullscreen mode Exit fullscreen mode

reducer が何もないという警告は消えた。


feature/counter/Counter.tsx で useSelector, useDispatch で slice と reducers を使う描画コンポーネントを作る

tsx じゃないと jsx の html っぽいものを使えない。

feature/counter/Counter.tsx に

https://react-redux.js.org/tutorials/quick-start#use-redux-state-and-actions-in-react-components

これらを App で使うためのコンポーネントを書く。

counterSlice によってグローバルに定義された counter
これを useSelector によって取ってきて
increment, decrement, incrementByAmount の reducers
これを インポートしてきて、dispatch によって動かせるようにする。

Counter.tsx に

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
import styles from './Counter.module.css'

export function Counter() {
  const count = useSelector((state) => state.counter.value)
  const dispatch = useDispatch()
Enter fullscreen mode Exit fullscreen mode

useSelector と useDispatch
increment と decrement
これらを持ってきて
持ってくるるのと発火せるロジックを作り

  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          Increment
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          Decrement
        </button>
      </div>
    </div>
  )
Enter fullscreen mode Exit fullscreen mode

ボタンで increment, decrement を dispatch させ
count を select で表示させる


App で import する

import { Counter } from './features/counter/Counter';
...
        <img src={logo} className="App-logo" alt="logo" />
        <Counter />
Enter fullscreen mode Exit fullscreen mode

Counter コンポーネントをインポートして
画像の下にレンダーされるようにする


動作確認

Image description

ブラウザで動くのを確認した。


まとめ

index.js に Provider で App のルートを括り、store を繋げる

ストアファイルを作って、configureStore として reducer たちを入れるところを作る

createSlice を使って counterSlice というコンポーネントを作り
name でグローバルステートの名前を counter と決めて
reducers に state の操作用に increment, decrement を作る

ストアファイルに counter を登録する

Counter というページコンポーネントを作って
useSelector でグローバルステートの counter を呼び、
useDispatch で reducer である increment, decrement を呼び
counter を表示し、ボタンで increment, decrement を使うロジックと UI を書く。

これで react-redux と redux toolkit を使って
counter の値を increment/decrement するアプリを作れた。


今後

使われていなかった incrementByAmount を CounterSlice で使えるようにし、新しく incrementAsnync も作り、これも使えるようにする。

このチュートリアルの現バージョンのドキュメントでは
incrementByAmount を使っていない。サンドボックスを見ると導入コードがあり、そこには incrementAsync というゆっくり反映されるボタンもあったので、ついでに作ってみる。

Top comments (0)