iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 13
0
Modern Web

React + GraphQL 全端練習筆記系列 第 13

仿Trello - 建立 Redux Store

本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。

簡介完Redux運作的概要後,進入實作,不過實作上跟上篇的流程有很大的差異,骨子裡相同但是會用 redux toolkit 的建立slice方法包裝起來用。

安裝 Redux toolkit

使用redux toolkit,裡面已經包含Redux:

npm install @reduxjs/toolkit

如果是新開的專案,可以在creat-react-app時選擇模板:

npx create-react-app my-app --template redux

建立 Slice

在src底下開兩個資料夾,分別叫做container跟reducer。

reducer裡建立兩個檔案index.js跟todosSlice.js :

//index.js
import { combineReducers } from "redux";
import todosReducer from "./todosSlice";

export default combineReducers({
  todos: todosReducer,
});
//todosSlice.js
import { createSlice } from "@reduxjs/toolkit";

const dummyData = [...]; //原本寫在KanBan.jsx裡的假資料

const todosSlice = createSlice({
  name: "todos",
  initialState: dummyData,
  reducers: {},
});

export default todosSlice.reducer;

先從Slice開始介紹,createSlice是redux toolkit提供的方法,它可以在同一個方法中定義state、action、跟reducer,並根據定義產出reducer跟action creators。

用createSlice來生成slice:

  • name : 這個slice的名稱。
  • initialState : 這個slice中state的初始值
  • reducers: 定義action type與對應的更新state方法,之後CRUD都寫在這。

Slice的用意在於把store切分成小塊管理,之後在把每個slice產生的reducer合併成一個root reducer後綁定給store。

而slice中定義的action 也會在前面帶上各自slice的名稱前綴,像是todos slice中的 addTodo 變成 "todos/addTodo",這樣一來如果不同slice中有同名的action,也會因為不同的前綴被store視為不同action,降低了action命名的複雜度。

雖然現在只有todos這個slice,不過為防以後新建更多的slice,要先用combineReducers包成一包。

export default combineReducers({
  todos: todosReducer,
  //未來的其他reducer加在這
});

串接App與Store

接著我們到 src/index.js中,用剛剛包好的root reducer創建store並綁到App上。

import { configureStore } from "@reduxjs/toolkit";
import { Provider } from "react-redux";

// 從reducers/index取得combineReducers回傳的物件
import rootReducer from "./reducers"; 

const store = configureStore({  //初始化store並綁定reducer
  reducer: rootReducer,
});

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}> //綁定store
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

這樣在App底下就能存取到store了。

傳 Todos 給 KanBan

在containers資料夾底下建立 KanBanContainer.js

// KanBanContainer.js
import { connect } from "react-redux";
import KanBan from "../components/KanBan";

const mapStateToProps = (state) => ({
  todos: state.todos, //將state 中的todos存為todos prop
});

//用connect將KanBan包上資料層,產生新的KanBanContainer部件
export default connect(mapStateToProps)(KanBan);

另外做一個container用意在於,區隔資料層(Data)與顯示層(View)。
KanBanContainer 負責處理資料相關的事情,並把state裡的todos傳給KanBan,KanBan則專心負責處理render需要的JSX部分。

接著在KanBan裡就能取得todos這個prop。

把lists 替換成 todos,清單就會改成用Redux store裡的資料顯示,不過別急著刪掉lists的useState,現在還有一大串葡萄依賴在上面,刪掉會大爆炸。

//KanBan.jsx
export default function KanBan({ todos }) {
  
  //...
  
   return (
    <>
      <KanBanNav />
      <div className="board  p-1">
        {todos.map((list, index) => (...))} //替換掉lists
        //...
      </div>
    </>
  );
  }

而在App.js裡,原本用的KanBan component要改為帶資料層的KanBanContainer。

//App.js
//      原本是 from "./components/KanBan";
import KanBan from "./containers/KanBanContainer";

function App() {
  return (
    <div className="App ">
      <KanBan></KanBan>
    </div>
  );
}

這樣就成功讓部件從Redux的Store裡存取需要的資料,接著要一個個把原本更新lists的方法以todosSlice裡的reducer替代。

References:

tags: 2020Ironman React tutorials

上一篇
Redux 簡介
下一篇
仿Trello - 製作reducer
系列文
React + GraphQL 全端練習筆記30

尚未有邦友留言

立即登入留言