Redux Toolkit
Redux Toolkitとは(React環境での解説になります)
ざっくり言うと、「データの状態」と「データの処理方法」をまとめて管理、記述できるもの。
まずは、Store、Slice という概念があります。
■Store
Slice全体を管理しているでっかい倉庫(Amazon)
■Slice
各種データを管理している区域の様なもの
■まずは「データの状態」だけでReduxの中身を見てみる
Redux Toolkit の中身について、ほぼフォルダ構造としてイメージ出来るので理解しやすいと思います。
// テキストで書き出すと以下の様なイメージ store // Slice全体を管理しているでっかい倉庫(Amazon) ├ book // Sliceの名前で、区分している(区域、フォルダの様なもの) └ camera // // これをもっと階層を掘り下げるとこんな感じでデータが管理されてます。 store ├ book │ itemList: { │ {id: 1, name: 'React入門'}, │ {id: 2, name: 'Redux Toolkit入門'}, │ } └ camera itemList: { {id: 1, name: 'Nikon D850'}, {id: 2, name: 'Nikon D800'}, }
■sliceに書き起こしてみる
// Book.ts import { createSlice } from "@reduxjs/toolkit"; // 初期値として入れたいデータ // 本来はAPIで取得したDBのデータを格納するが、ここではダミーを作成して説明 const bookItems = { {id: 1, name: 'React入門'}, {id: 2, name: 'Redux Toolkit入門'}, } // stateの初期状態(このSliceで扱う全データの初期状態) // stateとは、データ全体、オブジェクトで、stateを更新するにはreducerを使う。 const initialState = { itemList: bookItems }; // Sliceを生成する const bookSlice = createSlice({ name: "book", // Sliceの名前 initialState, // データの初期状態(上記のinitialStateがここで適応される) reducers: { // データの処理について記述 // 一旦省略 } }); // Reducerをエクスポートする export default bookSlice.reducer;
// Camera.ts import { createSlice } from "@reduxjs/toolkit"; const cameraItems = { {id: 1, name: 'Nikon D850'}, {id: 2, name: 'Nikon D800'}, } const initialState = { itemList: cameraItems }; const cameraSlice = createSlice({ name: "camera", initialState, reducers: { // 一旦省略 } }); // Reducerをエクスポートする export default cameraSlice.reducer;
■SliceをStoreに読み込む
import { combineReducers } from "redux"; import { configureStore } from "@reduxjs/toolkit"; // それぞれ slice.reducer を default export している前提 import bookReducer from "./book"; import cameraReducer from "./camera"; const reducer = combineReducers({ book: bookReducer, camera: cameraReducer }); const store = configureStore({ reducer }); export default store;
■結果
以下の様なイメージでStore(倉庫)の中のSlice(区域)にデータが入り、管理されます。
区域には、各ジャンル別にデータ(在庫)を置いているイメージです。
store book: itemList: { {id: 1, name: 'React入門'}, {id: 2, name: 'Redux Toolkit入門'}, } camera: itemList: { {id: 1, name: 'Nikon D850'}, {id: 2, name: 'Nikon D800'}, }
ここまでが「データの管理」までのざっくりとしたイメージです。
reducers
次に、処理の話です。
ここから少しだけ作業が増えますが、ゆっくり辿って確認していきましょう。
先に動きの結果だけ言うと
① reducersは、データ処理後の結果をstateに反映する
② stateが反映されるとstoreが更新される
③ sotreが更新されるとコンポーネントに反映される。
↓倉庫で例えると
① レジで清算を行う → 減った在庫をstateに反映する
② stateが更新される → 在庫データをstoreに反映する
③ storeが更新される → どのレジからsotreにアクセスしても在庫が反映されている状態を確認出来る
■処理イメージ
■処理
// Book.ts import { createSlice } from "@reduxjs/toolkit"; const bookItems = { {id: 1, name: 'React入門'}, {id: 2, name: 'Redux Toolkit入門'}, } const initialState = { itemList: bookItems }; const bookSlice = createSlice({ name: "book", initialState, reducers: { updateItemList: (state, action) => { // state.itemListは、initialStateの中のitemListの事をさしています。 // action.payloadは、state.itemListの中身に対して更新したい内容です。 state.itemList = action.payload } } }); export default bookSlice.reducer;
上記のコメントにもあるように「updateItemList」でstate(データ/オブジェクト)に更新をかけています。
そして、reduxの処理はこれで完了です。
では、在庫が増えた、減ったの処理はどうするのか?
それは、レジ = コンポーネント側で処理します。(本来は、処理専用の関数ファイルを用意しますが、ここではコンポーネントにまとめて説明します)
そして、その処理は普通のJavaScriptです。
■コンポーネント側で関数作って処理
では早速処理と言いたい所ですが、処理をする前に、在庫が分からないと処理ができません。
ですので、レジ = コンポーネントに、sotreを経由して在庫を読み込み、処理してみましょう。
// useSelectorは、Sliceの中身を読み込むためのもの // useDispatchは、Sliceのreducrsに処理の実行を依頼するために必要なもの import { useSelector, useDispatch } from "react-redux"; // Book.tsのreducersを読み込む import { updateItemList } from "../store/slice/Book"; const Component = () => { // dispatchとして定数に設定 const dispatch = useDispatch(); // useSelectorを使ってsliceで管理しているデータを読み込む const imteList = useSelector((state: RootState) => state.Book) const deleteItem = () => { // JavaScriptのpop()を使って配列の最後を削除 itemList.pop() // dispatchを使って更新を× dispatch(updateItemList(itemList)) } return ( <button onClick={deleteItem}>click</button> ); }
ここまで来ると、あとは普通にJavaScriptで処理しているだけです。
一応、流れを書き出すと
「const imteList = useSelector((state: RootState) => state.Book)」で、BookSliceで設定したitemLsitのデータが読み込まれます。
ここの解説で表すといかのデータです。
BookSlice itemList: { {id: 1, name: 'React入門'}, {id: 2, name: 'Redux Toolkit入門'}, }
そして「Component」のボタンを押すと「deleteItem」が実行されます。
「deleteItem」は、配列の最後を削除するという事なので、1回押せば次のように配列が変わります。
{ {id: 1, name: 'React入門'}, }
で「dispatch(updateItemList(itemList))」でSliceのreducersの「updateItemList」が実行されます。
updateItemList: (state, action) => { state.itemList = action.payload }
action.payload には、deleteItemで処理された「{id: 1, name: 'React入門’}」が渡されます。
そして、state.itemList = action.payload としてるので、
itemListの中身は「{id: 1, name: 'React入門’}」に書き換わります。
ここれで、データの更新が完了されました!
しかし、ここまでではありません。最後にSliceが更新されると
Storeに反映されBookSliceを読み込んでいるコンポーネントに
再レンダリングがかかり、コンポーネントも再描画されます。
ここまでが一連の流れです。
ここでは、ざっくり概要を掴みたい人に色々省略して書いたものです。
より詳しく知りたい方は、以下が参考になります。
ディスカッション
コメント一覧
まだ、コメントがありません