Getting Started: Resources to get started learning and using Redux">Getting Started: Resources to get started learning and using Redux">
跳到主要內容

Redux 入門

Redux 是用於可預測且可維護的全球狀態管理的 JS 函式庫。

它能協助您撰寫行為一致、在不同環境(用戶端、伺服器和原生)中執行,且易於測試的應用程式。除此之外,它還提供絕佳的開發人員體驗,例如 結合時間旅行除錯器的即時程式碼編輯

您可以將 Redux 與 React 或任何其他檢視函式庫一起使用。它非常小(包括相依項在內僅 2kB),但擁有大量的附加元件生態系統。

Redux Toolkit 是我們官方推薦用於撰寫 Redux 邏輯的方法。它包裝了 Redux 核心,並包含我們認為對建置 Redux 應用程式至關重要的套件和函式。Redux Toolkit 內建我們建議的最佳實務,簡化大多數 Redux 任務,防止常見錯誤,並讓撰寫 Redux 應用程式變得更容易。

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

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

安裝

Redux Toolkit

Redux Toolkit 可作為 NPM 上的套件取得,以搭配模組打包器或在 Node 應用程式中使用

# NPM
npm install @reduxjs/toolkit

# Yarn
yarn add @reduxjs/toolkit

建立 React Redux 應用程式

使用 React 和 Redux 建立新應用程式的建議方式是使用 針對 Vite 的官方 Redux+TS 範本,或使用 Next 的 with-redux 範本 建立新的 Next.js 專案。

這兩個範本都已針對該建置工具適當地設定 Redux Toolkit 和 React-Redux,並附帶一個小範例應用程式,展示如何使用 Redux Toolkit 的多項功能。

# Vite with our Redux+TS template
# (using the `degit` tool to clone and extract the template)
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app

# Next.js using the `with-redux` template
npx create-next-app --example with-redux my-app

我們目前沒有官方的 React Native 範本,但建議使用這些範本作為標準 React Native 和 Expo

Redux 核心

Redux 核心函式庫可作為 NPM 上的套件,供與模組打包器或在 Node 應用程式中使用

# NPM
npm install redux

# Yarn
yarn add redux

此套件包含一個預先編譯的 ESM 建置,可用作 <script type="module"> 標籤 直接在瀏覽器中。

如需更多詳細資訊,請參閱 安裝 頁面。

基本範例

應用程式的整個全域狀態都儲存在單一 儲存 內的物件樹中。變更狀態樹的唯一方法是建立一個 動作,一個描述發生事件的物件,並將其 發送 到儲存。若要指定狀態如何根據動作進行更新,您可以撰寫純粹的 reducer 函式,根據舊狀態和動作計算新的狀態。

Redux Toolkit 簡化了撰寫 Redux 邏輯和設定儲存的程序。使用 Redux Toolkit,基本的應用程式邏輯如下

import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})

export const { incremented, decremented } = counterSlice.actions

const store = configureStore({
reducer: counterSlice.reducer
})

// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))

// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}

您並非直接變異狀態,而是使用稱為 動作 的純粹物件指定您想要發生的變異。然後您撰寫一個稱為 reducer 的特殊函式,以決定每個動作如何轉換整個應用程式的狀態。

在典型的 Redux 應用程式中,只有一個儲存和一個根 reducer 函式。隨著應用程式成長,您會將根 reducer 拆分成較小的 reducer,獨立操作狀態樹的不同部分。這完全就像 React 應用程式中只有一個根元件,但它是由許多小元件組成的。

對於計數器應用程式來說,這個架構可能看起來很龐大,但此模式的優點在於它能很好地擴充到大型且複雜的應用程式。它也啟用了非常強大的開發人員工具,因為可以追蹤每個變異到導致它的動作。您可以記錄使用者工作階段,並透過重播每個動作來重現它們。

Redux Toolkit 讓我們可以撰寫更簡短且更易於閱讀的邏輯,同時仍然遵循相同的 Redux 行為和資料流程。

舊版範例

為了比較,原始 Redux 舊版語法(沒有抽象)看起來像這樣

import { createStore } from 'redux'

/**
* This is a reducer - a function that takes a current state value and an
* action object describing "what happened", and returns a new state value.
* A reducer's function signature is: (state, action) => newState
*
* The Redux state should contain only plain JS objects, arrays, and primitives.
* The root state value is usually an object. It's important that you should
* not mutate the state object, but return a new object if the state changes.
*
* You can use any conditional logic you want in a reducer. In this example,
* we use a switch statement, but it's not required.
*/
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}

// Create a Redux store holding the state of your app.
// Its API is { subscribe, dispatch, getState }.
let store = createStore(counterReducer)

// You can use subscribe() to update the UI in response to state changes.
// Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly.
// There may be additional use cases where it's helpful to subscribe as well.

store.subscribe(() => console.log(store.getState()))

// The only way to mutate the internal state is to dispatch an action.
// The actions can be serialized, logged or stored and later replayed.
store.dispatch({ type: 'counter/incremented' })
// {value: 1}
store.dispatch({ type: 'counter/incremented' })
// {value: 2}
store.dispatch({ type: 'counter/decremented' })
// {value: 1}

學習 Redux

我們有各種資源可幫助您學習 Redux。

Redux Essentials 教學課程

Redux Essentials 教學課程 是一個「由上而下」的教學課程,它教導「如何正確使用 Redux」,使用我們最新建議的 API 和最佳實務。我們建議從這裡開始。

Redux Fundamentals 教學課程

Redux Fundamentals 教學課程 是一個「由下而上」的教學課程,它從基本原理和沒有任何抽象教導「Redux 如何運作」,以及為什麼會有標準的 Redux 使用模式。

學習現代 Redux 直播

Redux 維護者 Mark Erikson 出現在「與 Jason 一起學習」節目中,說明我們建議如何使用 Redux。該節目包含一個現場編碼範例應用程式,展示如何使用 Redux Toolkit 和 React-Redux 鉤子與 TypeScript,以及新的 RTK Query 資料擷取 API。

請參閱 「學習現代 Redux」節目筆記頁面,以取得範例應用程式來源的逐字稿和連結。

其他教學課程

其他資源

協助與討論

#redux 頻道 of the Reactiflux Discord 社群是我們針對所有與學習和使用 Redux 相關問題的官方資源。Reactiflux 是個很棒的地方,可以閒逛、發問和學習 - 歡迎加入我們!

您也可以在 Stack Overflow 上使用#redux 標籤發問。

如果您有錯誤報告或需要提供其他回饋,請在 Github 儲存庫中提交問題

您是否應該使用 Redux?

Redux 是整理狀態的寶貴工具,但你也要考慮它是否適合你的情況。不要因為有人說你應該使用 Redux 就使用它 - 花點時間了解使用它的潛在好處和取捨

以下是一些建議,說明什麼時候使用 Redux 是有意義的

  • 你的資料量會隨著時間推移而發生合理的變化
  • 你需要一個狀態的單一真實來源
  • 你發現將所有狀態都保留在頂層元件中已不再足夠

有關 Redux 預期用途的更多想法,請參閱