【React】Redux toolkitの使い方(Slice作成、Redux Dev Toolsでstateを確認)
ReactでReduxを使う方法を紹介します。
ReactでReduxを使う方法
公式の手順は以下にあります。
https://react-redux.js.org/introduction/getting-started
実際はReactを作成してからReduxをいれることが多いと思うので、そのやり方を紹介します。
Reactのプロジェクトを作成
プロジェクトのファイルを作成します。
npx create-react-app [アプリ名]
npx create-react-app redux-app
ファイルのインストールが完了したら、cdでアプリ名のフォルダに移動します。
cd redux-app
そして、VS Codeなら以下コマンドで開けます。
code .
そして、以下コマンドで開発を始められます。
npm start
Reduxを既存のプロジェクトにいれる
以下コマンドで既存ReactプロジェクトにReduxをインストールできます。
npm install react-redux @reduxjs/toolkit
Reduxのプラグインを導入する
Chromeであれば、Redux DevToolsがあります。
そして、redux dev tools extensionで検索すると以下の拡張機能をgithubで配布している方がいるので、
それをいれます。
https://github.com/reduxjs/redux-devtools
最新は上記のURLになります。
また、拡張をする方法は、以下のページにかかれています。
https://github.com/reduxjs/redux-devtools/tree/main/extension#installation
やり方は簡単で、
<code class="language-javascript">const store = createStore( reducer, /* preloadedState, */ + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() );
上記のように+部分を追加するだけでOKです。
src/store.jsを作成
srcフォルダ直下にstore.jsを作成してstoreを作成します。
import { configureStore } from "@reduxjs/toolkit";
// storeにreducerをいれていく
export const store = configureStore({
reducer: {},
});
reduxのtoolkitをインストールすると、configureStoreを使えます。
storeはreducerを保持していくので、上のような形で記述していきます。
index.jsでstoreをアプリ全体で使えるようにする
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { store } from "./store"; //作成したstoreを追加
import { Provider } from "react-redux"; //Providerで全体でstoreを使えるようにする
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
作成したstoreとreact-reduxにあるProviderをインポートします。
そして、ProviderでAppをラップして、storeをpropsとして渡すことで、
アプリ全体で使えるようになります。
Sliceを作成
Sliceとはそもそも何?
Sliceとは、Storeというを輪切りにしたようなイメージです。
Storeはstate、Reducer、ActionCreatorを保持しています。
この3つ(state、Reducer、ActionCreator)の組み合わせをSliceといいます。
StoreはこのSliceをたくさん保持することができます。
src/features/cart/CartSlice.jsを作成
src以下は好きに名前をつければいいのですが、
今回は買い物かごのアプリを例にします。
src/features/cart/CartSlice.jsを作成して、以下を記述します。
import { createSlice } from "@reduxjs/toolkit";
// 買い物かごの初期化
const initialState = {
cartItems: [], // ひとつひとつの商品
amount: 0, // カートに入れた合計商品数量
total: 0, // 合計金額
}
const cartSlice = createSlice({
name: "cart", // sliceの名前、useSelectorでアクセスするときに使う
initialState, // 初期の状態
reducers: {}, // reducerを格納、actionCreatorはreducerを作成すると自動的に作られる
});
スライスは、@reduxjs/toolkit"のcreateSliceを使うことで作成できます。
オブジェクトの中に含むことは、スライスの名前、初期状態、reducersです。
スライスの名前は、useSelectorでアクセスするときに使います。
reducersでは、複数のreducerを格納することができます。
スライスには、actionCreatorも必要ですが、@reduxjs/toolkitを使えば、reducerを作成するとactionCreatorは自動的に作られます。
Redux Dev Toolsで確認できるようにする
src/features/cart/CartSlice.jsの最後に、以下を追加します。
export default cartSlice.reducer; // reducerをexport
createSliceで作成したスライスにはreducerというメソッドがあるので、それだけをエクスポートします。
そして、src/store.jsを以下のように書き換えます。
import { configureStore } from "@reduxjs/toolkit";
import cartReducer from "./features/cart/CartSlice"; // reducerをimport
export const store = configureStore({
reducer: {
cart: cartReducer, // reducerを追加
},
});
こうすることで、reducerのプロパティに格納した名前、上のケースではcartという名前で状態を確認することができます。
useSelectorでstoreにアクセスする
useSelectorでstoreにアクセスすることができます。
任意のコンポーネントで以下のようにインポートします。
import { useSelector } from "react-redux";
そして、以下のようにしてコンポーネント内で使用します。
const Component = () => {
// const amount = useSelector((store) => store.cart.amount);
const { amount } = useSelector((store) => store.cart);
console.log(amount);
return (
<div>{amount}</div>
);
};
上の例では、src/store.jsのreducerで設定した「cart」という変数にアクセスしています。
一般的には分割代入を使って必要な値のみを取り出します。
actionCreator
import { createSlice } from "@reduxjs/toolkit";
// 買い物かごの初期化
const initialState = {
cartItems: [], // ひとつひとつの商品
amount: 0, // カートに入れた合計商品数量
total: 0, // 合計金額
};
const cartSlice = createSlice({
name: "cart", // sliceの名前、useSelectorでアクセスするときに使う
initialState, // 初期の状態
reducers: {
// プロパティ名がactionCreatorとして作られる
clearCart: (state) => {
// 空にする
return { cartItems: [], amount: 0, total: 0 };
},
}, // reducerを格納、actionCreatorはreducerを作成すると自動的に作られる
});
// console.log(cartSlice); //actions.clearCartがある
export const { clearCart } = cartSlice.actions;
export default cartSlice.reducer; // reducerをexport
reducersの中にプロパティをセットして、関数で処理内容を記述します。
すると、自動的にプロパティ名でactionCreatorが作成されます。
コンソールで出力すると、actions.clearCartがあるのがわかります。
なので、それをエクスポートして利用します。
useDispatchで通知する
使いたいコンポーネントでまずは、インポートします。
import { useDispatch } from "react-redux";
そして、変数を作成します。
const dispatch = useDispatch();
そして、JSXでたとえばonClickで使います。
<button onClick={() => dispatch(clearCart())}>
全削除
</button>
そうすると、クリックイベントを機に通知されます。
ちなみにdispatchするときに引数に値を渡すとpayloadにセットされます。
reducers: {
removeItem: (state, action) => {
console.log(action);
}
},
上のようにたとえば、reducerにremoveItemという名前のプロパティを登録して、
ループしているコンポーネントの中で、以下のように使用します。
onClick={() => dispatch(removeItem(id))}
すると、actionの中にtypeとpayloadがあり、そのpayloadに各idが含まれます。titleならtitleがpayloadに入ります。