Reduxは状態管理のライブラリです。今回Reduxを使ってカウンターアプリを作成しました。
基本的な使い方になるのでメモしておきます!
用語や基本的な使い方はこちらの記事にまとめました。
サンプル:カウンターアプリ(JavaScript)
今回作成するカウンターアプリです。練習で作成する定番のアプリですね!
プルダウンメニューで増減する値を1、5、10から選べます。増減値をグローバル値として管理します。
実際の動きはこちらで確認できます!
サンプル:カウンターアプリ(TypeScript)
TypeScript版も作ったので今後の参考としてにメモしておきます。動きは全く同じです。
TypeScriptの使い方は、公式サイトで詳しく説明されています。
アプリの階層
アプリの階層は次のようになっています。
肝になるのはreduxディレクトリ以下のファイルです。
└── src
├── App.js
├── components
│ ├── Counter.js
│ ├── CounterBtn.js
│ ├── CounterResult.js
│ └── CounterSelect.js
├── index.js // ProviderコンポーネントでReduxの影響範囲を指定
├── logo.svg
├── redux
│ ├── counterSlice.js //reducer、actionに関する設定
│ └── store.js // sroreに関する設定
└── styles.css
Storeの構成
Storeにはcounterという名前のSliceが1つあります。
図にするとこんな感じです。
initialState(stateの初期値)のdisplaycountは画面に表示させる値で、settingcountは増減値になります。
reducerにstateの値を処理するコードを記述します。具体的には、値のプラス、マイナス、リセット、そして増減値のセットになります。
actionは[スライス名/タイプ名]で自動的に生成されます。
カウンターアプリ作成のポイント
カウンターアプリ作成のポイントを簡単にメモしておきます。
StoreにReducerを設定する
configureStore()でStoreを作成します。プロパティcounterに、createSlice()で作成するSliceを設定します。
redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import countReducer from "./counterSlice";
export const store = configureStore({
reducer: {
counter: countReducer // Reducerを設定する
}
});
SliceでReducerとActionCreatorを生成する
createSlice()でReducerとActionCreatorを生成します。
redux/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
// 初期値を設定
const initialState = {
displaycount: 0,
settingcount: 1,
};
const counter = createSlice({
name: 'counter',
initialState,
reducers: {
plus(state, action) {
console.log(action);
state.displaycount += state.settingcount;
},
minus(state, action) {
console.log(action.type, action.payload);
state.displaycount -= state.settingcount;
},
reset(state, action) {
console.log(action);
state.displaycount = 0;
},
// PayloadAction タイプを使用して、`action.payload の内容を宣言`
numSetting(action) {
console.log(action.type, action.payload);
state.settingcount = action.payload;
},
},
});
const { plus, minus, numSetting, reset } = counter.actions;
export { plus, minus, umSetting, reset };
export default counter.reducer;
最後にactionとreducerをエクスポートして、他のファイルで使用できるようにします。
React Toolkitを使ったReducerの設定
reducerは純粋関数である必要があります。
本来、次のように新しいオブジェクトを作成して、更新したstateをreturnで返します。
reducers: {
plus(state, action) {
const newPlus = {...state}
newPlus.displaycount = state.displaycount + state.settingcount;
return newPlus // 更新したstateを戻り値で返す
},
...省略
}
React Toolkitの場合、このようにstateを直接編集できます。returnも必要ありません。
reducers: {
plus(state, action) {
state.displaycount += state.settingcount;
},
...省略
}
ActionCreatorの設定
ActionCreatorは、createSlice()で自動的に生成されます。
createSlice()で生成したオブジェクト(今回はcounterオブジェクト)のactionsプロパティに含まれます。
// createSliceでreducerとactionクリエイターを生成
const counter = createSlice({
name: 'counter', // スライス名
initialState: {
displaycount: 0,
settingcount: 1,
},
reducers: {
// タイプ名でReducerを設定
plus(state, action) {
state.displaycount += state.settingcount;
},
...省略
}
})
// ActionCreatorを分割代入で取り出す
const { plus, minus, numSetting, reset } = counter.actions;
取得したActionCreatorは、分割代入で取り出すと使いやすいです。
なお、作成されたActionCreatorのタイプ名は、[スライス名/タイプ名]になります。
例){type: “counter/plus”, payload: 0 }
ReducerとActionCreatorをエクスポートする
最終的には、ReducerとActionCreatorをエクスポートします。
※Reducerはdefaultでエクスポートしています。
export { plus, minus, numSetting, reset };
export default counter.reducer;
StoreのReducerにcreateSlice()で作成したreducerを設定します。
今回、counterプロパティに設定しました。
defaultエクスポートしたオブジェクトは、名前を変更して読み込むことができるので、countReducerに名前を変更しました。
redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import countReducer from "./counterSlice";
export const store = configureStore({
reducer: {
counter: countReducer
}
});
Stateを表示する
stateはuseSelector()で取得できます。stateはStoreのプロパティ名に格納されています。
次のように取り出します。
import { useSelector } from "react-redux";
const CounterResult = () => {
const count = useSelector((state) => state.counter.displaycount);
// const count = useSelector((state) => state.counter.displaycount);
return <div className="result">{count}</div>;
};
export default CounterResult;
まとめ
今回、Reduxを理解するために簡単なカウンターアプリを作成しましたが、実際にはユーザーのログイン状態の管理に使うことが多いそうです。
アプリ作成には必須の知識となりそうなので、もう少し使い方に慣れたいと思います!