Why RTK is Redux Today: details on how RTK replaces the Redux core">Why RTK is Redux Today: details on how RTK replaces the Redux core">
跳至主要內容

為何 Redux Toolkit 是現今使用 Redux 的方式

什麼是 Redux Toolkit?

Redux Toolkit(簡稱「RTK」)是我們推薦撰寫 Redux 邏輯的官方建議方法。@reduxjs/toolkit 套件包含核心 redux 套件,以及我們認為建置 Redux 應用程式不可或缺的 API 方法和常見相依性。Redux Toolkit 內建我們的建議最佳實務,簡化大部分 Redux 任務,避免常見錯誤,並讓撰寫 Redux 應用程式變得更容易。

如果您今天撰寫任何 Redux 邏輯,您應該使用 Redux Toolkit 來撰寫該程式碼!

RTK 包含有助於簡化許多常見使用案例的公用程式,包括 設定儲存建立 reducer 和撰寫不可變更新邏輯,甚至 一次建立整個狀態「區塊」

無論您是設定第一個專案的全新 Redux 使用者,還是想簡化現有應用程式的經驗豐富使用者,Redux Toolkit 都能幫助您改善 Redux 程式碼。

提示

查看這些頁面,瞭解如何使用 Redux Toolkit 使用「現代 Redux」

Redux Toolkit 與 Redux 核心有何不同

什麼是「Redux」?

首先要問的是,「什麼是 Redux?」

Redux 實際上是

  • 包含「全域」狀態的單一儲存
  • 當應用程式發生某些事情時,傳送純粹物件動作至儲存
  • 純粹 reducer 函式查看這些動作,並傳回不可變更新的狀態

雖然不是必需的,您的 Redux 程式碼通常也包含

  • 產生那些動作物件的動作建立器
  • 啟用副作用的中介軟體
  • 包含具有副作用的同步或非同步邏輯的 Thunk 函數
  • 正規化狀態,以啟用透過 ID 查詢項目
  • 使用 Reselect 函式庫的記憶化選擇器函數,以最佳化衍生資料
  • Redux DevTools 擴充功能,以檢視您的動作歷程和狀態變更
  • 動作、狀態和其他函數的 TypeScript 類型

此外,Redux 通常與 React-Redux 函式庫一起使用,讓您的 React 元件可以與 Redux 儲存體對話。

Redux 核心有什麼作用?

Redux 核心是一個非常小且刻意不帶意見的函式庫。它提供了一些小的 API 原語

  • createStore,用於實際建立 Redux 儲存體
  • combineReducers,用於將多個切片還原器合併成一個更大的還原器
  • applyMiddleware,用於將多個中介軟體合併成一個儲存體增強器
  • compose,用於將多個儲存體增強器合併成一個儲存體增強器

除此之外,應用程式中所有其他與 Redux 相關的邏輯都必須完全由您撰寫。

好消息是,這表示 Redux 可以用許多不同的方式使用。壞消息是,沒有任何輔助程式可以讓您的程式碼更易於撰寫。

例如,還原器函數只是一個函數。在 Redux Toolkit 之前,您通常會使用 switch 陳述式和手動更新來撰寫該還原器。您可能還會手動撰寫動作建立器和動作類型常數

傳統手寫 Redux 使用方式
const ADD_TODO = 'ADD_TODO'
const TODO_TOGGLED = 'TODO_TOGGLED'

export const addTodo = text => ({
type: ADD_TODO,
payload: { text, id: nanoid() }
})

export const todoToggled = id => ({
type: TODO_TOGGLED,
payload: { id }
})

export const todosReducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return state.concat({
id: action.payload.id,
text: action.payload.text,
completed: false
})
case TODO_TOGGLED:
return state.map(todo => {
if (todo.id !== action.payload.id) return todo

return {
...todo,
completed: !todo.completed
}
})
default:
return state
}
}

這些程式碼都沒有特別依賴於 redux 核心函式庫的任何 API。但是,這需要撰寫大量的程式碼。不可變更新需要大量手寫物件擴充和陣列操作,而且很容易出錯,並在過程中意外變異狀態(始終是 Redux 錯誤的頭號原因!)。儘管不是絕對必要,但將一個功能的程式碼分散在多個檔案中(例如 actions/todos.jsconstants/todos.jsreducers/todos.js)也很常見。

此外,儲存設定通常需要一系列步驟來新增常用的中間件,例如 thunks,並啟用 Redux DevTools Extension 支援,即使這些是幾乎每個 Redux 應用程式中使用的標準工具。

Redux Toolkit 有什麼功能?

雖然這些原本是 Redux 文件中顯示的模式,但不幸的是,它們需要大量非常冗長且重複的程式碼。這些樣板程式碼大部分並非使用 Redux 所必需。除此之外,樣板程式碼會導致更多犯錯的機會。

我們特別建立 Redux Toolkit 來消除手寫 Redux 邏輯中的「樣板程式碼」,防止常見錯誤,並提供簡化標準 Redux 任務的 API。.

Redux Toolkit 從兩個關鍵 API 開始,簡化每個 Redux 應用程式中最常執行的工作。

  • configureStore 設定一個設定完善的 Redux 儲存,只需呼叫一次函式,包括合併 reducer、新增 thunk 中間件,以及設定 Redux DevTools 整合。它也比 createStore 更容易設定,因為它採用命名選項參數。
  • createSlice 讓您可以撰寫使用 Immer 函式庫 的 reducer,以啟用使用「變異」JS 語法(例如 state.value = 123)撰寫不可變更新,無需任何擴充。它也會自動為每個 reducer 產生動作建立函式,並根據 reducer 的名稱在內部產生動作類型字串。最後,它與 TypeScript 搭配使用效果極佳。

這表示您撰寫的程式碼可以大幅簡化。例如,相同的 todos reducer 可能只是

features/todos/todosSlice.js
import { createSlice } from '@reduxjs/toolkit'

const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
todoAdded(state, action) {
state.push({
id: action.payload.id,
text: action.payload.text,
completed: false
})
},
todoToggled(state, action) {
const todo = state.find(todo => todo.id === action.payload)
todo.completed = !todo.completed
}
}
})

export const { todoAdded, todoToggled } = todosSlice.actions
export default todosSlice.reducer

所有動作建立函式和動作類型都是自動產生的,而 reducer 程式碼也更短且更容易理解。每個案例中實際更新的內容也更清楚。

使用 configureStore,儲存設定可以簡化為

app/store.js
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'
import filtersReducer from '../features/filters/filtersSlice'

export const store = configureStore({
reducer: {
todos: todosReducer,
filters: filtersReducer
}
})

請注意,這一個 configureStore 呼叫會自動執行所有您手動執行的常見設定工作

  • 自動將 slice reducer 傳遞給 combineReducers()
  • 自動加入 redux-thunk 中介軟體
  • 加入開發模式中介軟體,以捕捉意外的變異
  • 自動設定 Redux DevTools 擴充功能
  • 將中介軟體和 DevTools 強化功能組合在一起,並加入儲存

同時,configureStore 提供選項,讓使用者修改任何這些預設行為(例如關閉 thunk 並加入 saga,或在生產環境中停用 DevTools)

從此,Redux Toolkit 包含其他 API,用於常見的 Redux 任務

  • createAsyncThunk:抽象標準「在非同步請求前/後發送動作」模式
  • createEntityAdapter:針對正規化狀態的 CRUD 操作預先建置的 reducer 和選擇器
  • createSelector:標準 Reselect API 的重新匯出,用於記憶化選擇器
  • createListenerMiddleware:用於執行邏輯以回應已發送動作的副作用中介軟體

最後,RTK 套件還包括「RTK Query」,這是一個完整的 Redux 應用程式資料擷取和快取解決方案,作為一個獨立的選用 @reduxjs/toolkit/query 進入點。它讓您可以定義端點(REST、GraphQL 或任何非同步函式),並產生一個 reducer 和中介軟體,以完全管理資料擷取、更新載入狀態和快取結果。它還會自動產生 React hook,可以在元件中用於擷取資料,例如 const { data, isFetching } = useGetPokemonQuery('pikachu')

這些 API 各自都是完全選用的,並針對特定使用案例設計,而且您可以挑選並選擇實際在應用程式中使用的 API。但是,強烈建議使用所有這些 API 來協助執行這些任務。

請注意,Redux Toolkit 仍然是「Redux」!仍然只有一個儲存,其中包含用於更新的已發送動作物件,以及不可變地更新狀態的 reducer,加上撰寫 thunk 以進行非同步邏輯、管理正規化狀態、使用 TypeScript 輸入程式碼以及使用 DevTools 的能力。您只需要撰寫更少的程式碼就能獲得相同的結果!

為何我們希望您使用 Redux Toolkit

身為 Redux 維護人員,我們的意見是

提示

我們希望所有 Redux 使用者使用 Redux Toolkit 編寫 Redux 程式碼,因為它簡化了您的程式碼消除了許多常見的 Redux 錯誤和問題!

早期 Redux 模式的「樣板」和複雜性從來都不是 Redux 的必要部分。這些模式只存在是因為

  • 原始的「Flux 架構」使用了其中一些相同的方法
  • 早期的 Redux 文件顯示了動作類型常數等內容,以便按類型將程式碼分隔到不同的檔案中
  • JavaScript 預設為可變語言,而寫入不可變更新需要手動物件擴充和陣列更新
  • Redux 最初僅在幾週內建置,並故意設計為僅有幾個 API 原語

此外,Redux 社群採用了一些特定方法,增加了額外的樣板

  • 強調使用 redux-saga 中介軟體作為編寫副作用的常見方法
  • 堅持手寫 Redux 動作物件的 TS 類型,並建立聯集類型以限制可以在類型層級中調用的動作

多年來,我們見識到人們實際上如何使用 Redux。我們見識到社群為產生動作類型和建立函式、非同步邏輯和副作用,以及資料擷取等任務編寫了數百個附加函式庫。我們也見識到持續讓我們的使用者感到痛苦的問題,例如意外變異狀態、僅為了進行一個簡單的狀態更新而寫入數十行程式碼,以及難以追蹤程式碼庫如何整合在一起。我們協助了數千名嘗試學習和使用 Redux 的使用者,他們努力了解所有部分如何整合在一起,並對他們必須編寫的概念數量和額外程式碼感到困惑。我們知道我們的使用者面臨哪些問題。

我們特別設計了 Redux Toolkit 來解決這些問題!

  • Redux Toolkit 將儲存設定簡化為單一的明確函式呼叫,同時保留在需要時完全設定儲存選項的能力
  • Redux Toolkit 消除了意外變異,這一直是 Redux 錯誤的頭號原因
  • Redux Toolkit 消除了手寫任何動作建立函式或動作類型的需要
  • Redux Toolkit 消除了編寫手動且容易出錯的不可變更新邏輯的需要
  • Redux Toolkit 讓您可以在一個檔案中輕鬆編寫 Redux 功能的程式碼,而不是將其分散在多個不同的檔案中
  • Redux Toolkit 提供了出色的 TS 支援,其 API 旨在為您提供出色的類型安全性,並將您必須在程式碼中定義的類型數量降至最低
  • RTK Query 可以消除編寫任何 thunk、reducer、動作建立函式或效果掛勾以管理資料擷取和追蹤載入狀態的需要

因此

提示

我們特別建議我們的用戶應該使用 Redux Toolkit(@reduxjs/toolkit 套件),並且不應該將舊版的 redux 核心套件用於任何新的 Redux 程式碼!

即使對於現有的應用程式,我們建議至少將 createStore 切換為 configureStore,因為開發模式中介軟體也能幫助您在現有的程式碼庫中偵測到意外的變異和可序列化錯誤。我們也鼓勵您將您最常使用的 reducer(以及您未來撰寫的任何 reducer)切換到 createSlice - 程式碼會更簡短且更容易理解,而安全性改善會節省您未來投入的時間和精力。

redux 核心套件仍然有效,但我們現在認為它已過時。它的所有 API 也都從 @reduxjs/toolkit 重新匯出,而 configureStore 會執行 createStore 所做的所有事情,但預設行為和可設定性更好。

了解較低層級的概念很有用,這樣您才能更了解 Redux Toolkit 為您執行了哪些動作。這就是 「Redux 基礎」教學課程會說明 Redux 如何運作,且沒有任何抽象 的原因。但是,它展示這些範例純粹作為學習工具,並在最後說明 Redux Toolkit 如何簡化舊版手寫 Redux 程式碼。

如果您單獨使用 redux 核心套件,您的程式碼將會繼續運作。但是,我們強烈建議您切換到 @reduxjs/toolkit,並更新您的程式碼以使用 Redux Toolkit API!

進一步資訊

請參閱這些文件頁面和部落格文章以取得更多詳細資訊