概述
Redux 常見名詞解釋
- React-Redux:一個套件,讓 React 跟 Redux 可以一起使用,幫助 React 元件輕鬆讀取或更新 Redux 的狀態。
- Action:一個物件,用來描述發生了什麼事情,包含改變應用程式狀態需要的資訊。
- Reducer:一個純函式,負責接收 action 和目前的狀態,然後回傳更新後的新狀態。
- Store:一個物件,負責保存應用程式的所有狀態,並提供方法來讀取狀態或監聽狀態的變化。
- Dispatch:一個函式,負責把 action 傳給 reducer,進而觸發狀態的改變。
- Middleware:一個可以延伸 dispatch 功能的工具,常用來處理非同步操作、記錄日誌或錯誤處理等。
- Selector:一個函式,用來從狀態中挑選出需要的資料,讓 React 元件更方便拿來用。
為何需要 Redux ?
原本在 React 中,使用 createContext 可以定義一個 context,並在 provider 中指定要共享的 state 結構,這樣可以在元件之間傳遞 props。例如:
1 | import React, { createContext, useState } from "react"; |
然而,當需要管理大量的 context 時,專案中的階層變複雜,state 和 props 變的很多,資料在多層 component 之間的傳遞也越來越多,就會產生一堆純粹用來傳遞用的 props 和父 component。為了提高可維護性,需要使用更有效的方法。
React 專案導入 Redux 主要目的
集中管理狀態
:Redux 把應用程式的狀態統一存放在 store 裡,方便管理。不需要東一塊、西一塊的處理狀態,讓整體更有條理,也更好維護。簡單取得狀態
:用 Redux 可以在應用的任何地方直接存取狀態,不需要一直用 props 一層層傳遞資料,省時又方便。好調試、支援時間回溯
:Redux 的狀態改變都是透過 action,這讓我們可以回溯應用程式的狀態
,檢查不同時間點的狀態變化,對於調試和測試超級有幫助。容易整合其他套件
:Redux 是一個獨立的套件,可以輕鬆跟其他工具搭配使用,比如用 React-Redux 把 Redux 接到 React 裡,或用 Redux-Saga 處理非同步邏輯。避免不必要的重渲染
:Redux 可以有效管理狀態,當狀態改變時,只有用到這些狀態的元件會重新渲染。這能減少多餘的重繪,提升效能。
觀念
它們之間的關係是 action 觸發 reducer 更新 store 中的 state。
三個核心概念
action
:action 描述 state 改變reducer
:reducer 根據 action 更新 statestore
::store 存儲 state 並提供存取
三原則
- 單一資料來源 (Single source of truth):整個 App 的資料狀態(state)都被存儲在一個稱為 “store” 的物件中,方便維護和操作。
- 可變的狀態(State is read-only):要改變資料狀態的唯一方式就是透過 action,而不是直接修改狀態本身。這樣可以讓應用程式的狀態變更變得可追蹤、可預測,也更容易進行調試和測試。
- 使用純函數來進行修改(Change are made with pure functions):狀態的變更 abstract 成一個稱為 “reducer” 的純函數,該函數接收一個舊的 state 和一個 action,並返回一個新的 state 。純函數可以避免副作用和 state 變化的不可預測性。
Redux 運作流程 (data flow)
元件
Action、Action Creators 和 Bound Action Creator
action 是描述狀態變更的純 JavaScript 物件(object)。它必須包含一個「type」屬性,用來描述要發生的事件(說明想要對資料做哪些改變),並且可以包含任意額外的資料 (payload)。
1 | // action creater |
這邊範例定義了一個名為「increaseCount」的 action,它將 type 設置為「INCREASE_COUNT」,並且在 payload 中傳遞了一個名為「amount」的數值。當這個 action 被 dispatch 到 store 中時,它將會觸發狀態的變更,進而影響應用程式的行為。
通常會在一個獨立的檔案中定義所有的 action,然後在需要的地方引用它們。使用 Redux 提供的 action 創建函數,我們可以輕鬆地創建一個新的 action 物件,並將其 dispatch 到 store 中。
1 | // Bound Action Creator dispatch action |
Reducers 更新與改變 State
rreducer 是一個純函式(function)
,reducer 接收先前的 state 和一個 action,並回傳新的 state。reducer 是用來處理 action 的,它會判斷 action 的 type,然後根據不同的 type 做出不同的處理。
1 | const initialState = { |
在這個範例中,定義了一個名為「counterReducer」的 reducer,它會對應到一個名為「count」的狀態屬性。當 reducer 接收到一個 action 時,它會檢查 action 的 type,然後決定如何處理狀態的更新。在這個例子中,我們使用 switch/case 來處理兩種不同的 action:
- 當 action 的 type 為「INCREASE_COUNT」時,我們會將 count 屬性增加 action.payload.amount 的值。
- 當 action 的 type 為「DECREASE_COUNT」時,我們會將 count 屬性減少 action.payload.amount 的值。
- 2如果 action 的 type 不符合上述任何一個條件,則直接回傳原始的 state。
reducer 必須是一個純函式,也就是說,它不能有任何副作用,必須總是返回一個新的 state。這種限制可以確保 Redux 的行為可預測,並且簡化了程式的測試和調試。
Store 儲存所有 State
state 統一存在 “store” 物件中,方便維護和操作,在 Redux 中只會有一個 store,但可以有多可 reducer
。
state 是一個包含所有應用程式狀態的物件。為了避免直接修改 state,Redux 採用了 immutable
的概念,也就是每次更新狀態都必須回傳一個全新的 state 物件,而不是修改原有的 state 物件。
所以才常看到用 spread operator 來複製一個新的 state 物件的寫法:
1 | export const userDetailReducer = (state = {}, action) => { |
這樣的寫法有幾個好處:
在 Redux 中,我們可以使用 store.getState() 方法來獲取當前的 state 物件,但不能直接修改它。我們必須通過發送 action 來更改 state
,並且這個更改必須在 reducer 中進行。由於 reducer 是純函式,因此我們可以安全地修改 state,並在每個 action 被處理後返回一個新的 state 物件。
- 它可以使 Redux 的行為更可預測,因為我們不會意外地修改 state 物件。
- 它使我們可以更輕鬆地進行調試和測試,因為我們可以比較新舊兩個 state 物件,並檢查它們的差異。
- 它可以使我們更容易地實現時間旅行(time travel)功能,即將應用程式回到過去的狀態。
1 | import { configureStore } from "@reduxjs/toolkit"; |
簡單來說,在 Redux 中,state 是一個包含應用程式狀態的物件,它可以被修改,但必須在 reducer 中進行,並且每次修改都必須返回一個新的 state 物件。
參考資料
- https://pjchender.dev/react/redux-basic/#actionaction-creators-%E5%92%8C-bound-action-creator
- https://redux.js.org/usage/
若您覺得這篇文章對您有幫助,歡迎分享出去讓更多人看到⊂◉‿◉つ~
留言版