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)