React + React-Redux + Redux-Toolkit 新手教學

一個平凡的下午,小口小口啜飲著有點燙口的紅茶拿鐵,突然看到前端對話群組掀起一陣討論,討論著新案子的style解決方案,是要用上次我們一起看到的 Taiwindcss 呢?還是 styled-components 呢?

眾多討論串中,我看到了一句話,讓我的下午變得再也不平凡…

他是這樣說的:

你們決定好就好,但資料流的部分我先安裝 Saga 囉!

等等!那是什麼東西?上網查了一番…是在Redux的基礎上又有一些資料流程的處理工具。

我連Redux都沒用過啊~~(尖叫)

於是先來一篇 Redux 基本功~ 等我學會 Saga 說不定又可以在寫一篇 Saga 的XDD


一開始要先做點功課

首先我們先看官網的介紹,要使用 Redux 的話,推薦可以安裝 Redux-Toolkit,讓編寫 Redux 的過程可以更整齊bla bla…

Redux 也有提供他們使用 Redux-Toolkit 寫好的範例,可以從這邊下載下來看。

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

 

使用 Redux,你會聽到幾個關鍵字:

  1. state:有點類似宣告變數,就是存放資料和狀態的地方。
  2. reducer:用來修改state的橋樑。在 Redux,你要動到state的狀態,一定要透過 reducer
  3. actionreducer要修改state的話,需要傳入action,也就是說reducer要作用的話一定要傳入一個action去判斷要啟動哪個reducer
  4. Provider:在所有組件的最外面(通常是Index.js)包一層Provider,傳入store,所有被包覆的組件都可以使用到store的狀態。
  5. store:就是statereduceraction的集合,換句話說,放statereduceraction的那隻檔案就叫做store。 

 

Redux 的流程大概會是這樣:

  • 創建Store,用來裝所有要集中處理的資料和方法的地方
  • 在最外層使用Privider把整個 App 包起來,讓所有的組件都可以使用到Store內的資料和方法。
  • 撰寫slice,裡面會存放states(資料)和reducers(方法)。
  • 在專案內讀取這些資料或更新這些資料。

 

安裝環境

一開始你會有一個 react 專案

$ npx create-react-app my-project

然後安裝我們的主角~~~

$ yarn add react-redux @reduxjs/toolkit

 

創建Store

新增一個檔案store/index.js

import { configureStore } from "@reduxjs/toolkit";
import todoReducer from "./slice/todo";

export default configureStore({
  reducer: {
    todo: todoReducer,
  },
});

configureStoretoolkit的創建store參數,如果你沒有使用toolkit,Redux 有原生的參數可以使用。

你會發現我們在這邊引用了一個slice檔案(等等會創建這個檔案),也就是說你日後會在這邊引入很多slice,可能是order訂單、customer客戶…等,像是幫資料分類的概念。

類似這樣:

import { configureStore } from "@reduxjs/toolkit";
import todoReducer from "./slice/todo";
import orderReducer from "./slice/order";

export default configureStore({
  reducer: {
    todo: todoReducer,
    order: orderReducer,
    // ...
  },
});

 

在App.js加入Provider

在這邊要把provider包在最外面,這樣才會整個專案都可以存取到。

放在index.js也可以,只要是最外層就好,但我不是很喜歡我的邏輯去放到index.js,所有修改都從App.js開始就好ㄌ。

import { Provider } from "react-redux";
import store from "@/store";

function App() {
  return (
    <Provider store={store}>
      //...
    </Provider>
  );
}

export default App;

 

創建Slice

slicetoolkit的概念,他是把 Redux 原生的statereduceraction都合在一包,並且叫它slice

所以看下面程式碼就知道,裡面會包含上述這些東西。

 

創建store/slice/todo.js

import { createSlice } from "@reduxjs/toolkit";
export const todoSlice = createSlice({
  name: "todo",
  initialState: {
    //...
  },
  reducers: {
    //...
  },
});

createSlicetoolkit的工具,如果你沒有使用toolkit,就要自己創建statesreducersactions

首先我們從toolkit引入createSlice,創建的時候裡面要放物件:

  • initialState:就是放所有狀態初始值,但是slice裡就只需要設定initialState,不需要設定state
  • reducers:通常是放很多的函式,會有兩個參數stateactionstate就是讓你修改狀態,你可以直接對state進行操作;action就是讓你傳入參數。

放好之後會類似這樣:

import { createSlice } from "@reduxjs/toolkit";
export const todoSlice = createSlice({
  name: "todo",
  initialState: {
    todolist: [
      { id: 1, name: "first todo on redux" },
      { id: 2, name: "second todo in list" },
    ],
  },
  reducers: {
    addTodo: (state, action) => {
      state.todolist.push(action.payload);
    },
  },
});

 

在畫面中引用

我會有兩個檔案,一個是顯示 todo list 的 component,然後在首頁放進這個 component,並且首頁也會有一顆按鈕,可以直接新增 todo。

src/
 --- components/
     --- Todolist.js
 --- store/
     --- slice/
         --- todo.js
     --- index.js
 --- App.js

因為按鈕和 todo list 是在不同檔案,這時候就是 Redux 最重要的存在意義,存取全域的資料,讓不同的 component 同時能拿到最新資料狀態。

輸出sliceselector

import { createSlice } from "@reduxjs/toolkit";
export const todoSlice = createSlice({
  name: "todo",
  initialState: {
    todolist: [
      { id: 1, name: "first todo on redux" },
      { id: 2, name: "second todo in list" },
    ],
  },
  reducers: {
    addTodo: (state, action) => {
      state.todolist.push(action.payload);
    },
  },
});

export const selectTodo = (state) => state.todo; // <---加入這行

建立components/TodoList.js

import React from "react";
import { useSelector } from "react-redux";
import { selectTodo } from "../store/slice/todo";
const TodoList = () => {
  const states = useSelector(selectTodo); // <-- 拿取資料
  return (
    <ul>
      {states.todolist.map((i) => (
        <li key={i.id}>{i.name}</li>
      ))}
    </ul>
  );
};

export default TodoList;
  • useSelector:要拿取state,就要使用 Redux 的 useSelector api,傳入你在slice建立的Selector

 

這時候你的 component 已經可以取得 Redux 的資料了。

那如果我們想要在頁面中引入 component,並且頁面要直接改變 Redux 的資料呢?

我們在App.js中引入剛剛創建的Todolist.js

import TodoList from "./components/TodoList";
//...
<TodoList />

你可以看到這邊我們並沒有傳入任何資料給 <Todolist />,因為他已經是抓取 Redux 的資料,而不是依賴父元件的props

 

還記得在slice中我們有創建一個addTodoreducer

export const todoSlice = createSlice({
  name: "todo",
  initialState: {
    //...
  },
  reducers: {
    addTodo: (state, action) => { // <-- 這邊~~~~~~
      state.todolist.push(action.payload);
    },
  },
});

 

要取用reduce的話,必須傳入一個action

但是在Toolkit中,他已經幫我們創建好了,所以我們只要輸出讓頁面可以取用就好。

export const todoSlice = createSlice({
  name: "todo",
  initialState: {
    //...
  },
  reducers: {
    addTodo: (state, action) => {
      state.todolist.push(action.payload);
    },
  },
});

export const { addTodo } = todoSlice.actions; // <-- 加上這行

 

App.js中取用reducer並且傳入action

import { useDispatch } from "react-redux";
import { addTodo } from "./store/slice/todo";

function App() {
  const dispatch = useDispatch();

  const handleAddTodo = () => {
    dispatch(
      addTodo("a new todo item");
    );
  };
  return (
    <TodoList />
    <button onClick={handleAddTodo}>add todo</button>
  )
}

這樣子點下按鈕,就可以直接更新 Redux 的資料,所有有呼叫 Redux 的todo資料的組件都會同步更新囉!

學習程式原來可以這麼簡單:六角學院線上課程

初學者如何成為vue前端工程師:查看課程內容

---------------------------

| 軟體開發 | 網站建置 | 網頁系統 | 資料庫網站 |

| 客製化網站 (報名系統、投票系統、掛號系統...) |

| 前後端技術合作 |

歡迎與我們聯繫:jessica@penueling.com

加入Line立即聊聊:@539mjyid

1+
0 回復

發表評論

Want to join the discussion?
Feel free to contribute!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。