學習如何使用 Redux
Redux 是一個狀態管理器,通常與 React 一起使用,但並不限於該庫。通過閱讀這個簡單且易於理解的指南,來學習 Redux。
為什麼需要 Redux
Redux 是一個狀態管理器,通常與 React 一起使用,但它並不限於該庫 - 它也可以與其他技術一起使用。React 有自己的狀態管理方式,你可以在 React 初學者指南 中了解有關在 React 中管理狀態的方法。
將狀態向上移動到樹中適用於簡單的情况,但在複雜的應用程序中,你可能會發現你需要將幾乎所有的狀態向上移動,然後再使用 props 將其向下傳遞。
React 在 16.3.0 版本中引入了上下文 API,從不同部分訪問狀態的用例中,這使得 Redux 變得多餘,因此可以考慮使用上下文 API 而不是 Redux,除非你需要 Redux 提供的特定功能。
Redux 是一種管理應用程序狀態並將其移至外部全局存儲區的方法。有一些概念需要掌握,但一旦掌握,Redux 可以非常簡單地解決問題。
Redux 在 React 應用程序中非常流行,但它不僅僅適用於 React:幾乎有任何流行框架的綁定。那麼,我將使用 React 做一些示例,因為這是它的主要用例。
何時應該使用 Redux?
Redux 適用於中大型應用程序,在使用 React 或其他庫的默認狀態管理時遇到問題時,應把它用於項目中。
簡單的應用程式不需要它(簡單的應用程式沒有問題)。
不可變的狀態樹
在 Redux 中,應用程序的整個狀態由一個名為狀態或狀態樹的 JavaScript 對象表示。
我們稱其為不可變的狀態樹,因為它是只讀的:不能直接更改它。狀態只能通過分發動作來更改。
Actions
動作是一個以最小方式描述變更的 JavaScript 對象(僅帶有所需的信息):
1 | { |
動作對象的唯一要求是具有type
屬性,其值通常是一個字符串。
Action types 應該是常數
在簡單的應用程序中,動作類型可以定義為字符串。
當應用程序增長時,最好使用常數:
1 | const ADD\_ITEM = 'ADD\_ITEM' |
並將動作分離到自己的文件中,並導入它們:
1 | import { ADD\_ITEM, REMOVE\_ITEM } from './actions' |
Action creators
動作創建器是創建動作的函數:
1 | function addItem(t) { |
通常與觸發調度程序一起運行動作創建器:
1 | dispatch(addItem('Milk')) |
或通過定義動作調度程序函數來運行它:
1 | const dispatchAddItem = i => dispatch(addItem(i)) |
Reducers
當動作被觸發時,必須發生某些事情,應用程序的狀態必須發生變化。這是reducer的工作。
什麼是 reducer
reducer是一個純函數,它根據先前的狀態樹和分發的動作計算下一個狀態樹:
1 | ;(currentState, action) => newState |
純函數在不更改輸入或其他任何東西的情況下接收輸入並返回輸出。因此,reducer 返回一個完全替換先前狀態的全新狀態。
Reducer 不應該做什麼
reducer 應該是一個純函數,因此它應該:
- 永遠不要更改它的參數
- 永遠不要更改狀態,而是使用
Object.assign({}, ...)
創建一個新的狀態 - 永遠不要生成副作用(不更改任何東西的 API 調用)
- 永遠不要調用非純函數,這些函數根據與其輸入不同的因素改變其輸出(例如,
Date.now()
或Math.random()
)
沒有強制執行,但你應該遵守這些規則。
多個 reducer
由於複雜應用的狀態可能非常廣泛,因此不只有一個 reducer,而有多個用於任何類型的動作。
reducer 的模擬
基本上,Redux 可以用這個簡單模型來簡化:
狀態
1 | { |
一系列的 actions
1 | { type: 'ADD\_ITEM', title: 'Third item' } |
每個部分的 reducer
1 | const title = (state = '', action) => { |
整個狀態的 reducer
1 | const listManager = (state = {}, action) => { |
Store
Store 是一個對象,它:
- 保持 app 的狀態
- 通過
getState()
公開狀態 - 通過
dispatch()
允許我們更新狀態 - 通過
subscribe()
允許我們(取消)註冊狀態變化監聽器
store 在應用程序中是唯一的。
下面是如何創建 listManager app 的 store:
1 | import { createStore } from 'redux' |
我可以使用服務器端數據初始化 store 嗎?
當然可以,只需傳遞起始狀態:
1 | let store = createStore(listManager, preexistingState) |
獲取狀態
1 | store.getState() |
更新狀態
1 | store.dispatch(addItem('Something')) |
監聽狀態變化
1 | const unsubscribe = store.subscribe(() => |
數據流
Redux 中的數據流始終是單向的。
在 store 上調用 dispatch()
,傳遞一個 action。
store 負責將 action 傳遞給 reducer,生成下一個狀態。
store 更新狀態並通知所有的監聽器。tags:Redux, JavaScript