Basic Reducer Structure: Overview of how reducer functions work with Redux state">Basic Reducer Structure: Overview of how reducer functions work with Redux state">
跳至主要內容

基本 Reducer 結構和狀態形狀

基本 Reducer 結構

首先,重要的是要了解你的整個應用程式實際上只有一個單一的 reducer 函數:你傳遞給 createStore 作為第一個參數的函數。那個單一的 reducer 函數最終需要做幾件事

  • 第一次呼叫 reducer 時,state 值將會是 undefined。reducer 需要透過在處理傳入動作之前提供一個預設狀態值來處理這個情況。
  • 它需要查看前一個狀態和已發送的動作,並決定需要做什麼樣的工作
  • 假設需要進行實際變更,它需要使用更新的資料建立新的物件和陣列,並回傳它們
  • 如果不需要變更,它應該回傳現有的狀態。

撰寫 reducer 邏輯最簡單的方法是將所有內容放入單一函數宣告中,如下所示

function counter(state, action) {
if (typeof state === 'undefined') {
state = 0 // If state is undefined, initialize it with a default value
}

if (action.type === 'INCREMENT') {
return state + 1
} else if (action.type === 'DECREMENT') {
return state - 1
} else {
return state // In case an action is passed in we don't understand
}
}

請注意,這個簡單的函數滿足了所有基本需求。如果沒有值,它會回傳預設值,初始化儲存;它根據動作的類型決定需要進行什麼類型的更新,並回傳新值;如果不需要工作,它會回傳前一個狀態。

可以對這個 reducer 進行一些簡單的調整。首先,重複的 if/else 陳述會很快變得令人厭煩,因此通常會改用 switch 陳述。其次,我們可以使用預設參數值來處理初始的「沒有現有資料」情況。有了這些變更,reducer 會如下所示

function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

這是典型 Redux reducer 函數使用的基本結構。

基本狀態形狀

Redux 鼓勵您從您需要管理的資料角度思考您的應用程式。在任何特定時間點的資料都是您的應用程式的「狀態」,而該狀態的結構和組織通常稱為其「形狀」。您的狀態的形狀在您如何建構您的 reducer 邏輯中扮演著重要的角色。

Redux 狀態通常有一個純 JavaScript 物件作為狀態樹的頂端。(當然也可以使用其他類型的資料,例如單一數字、陣列或專門的資料結構,但大多數函式庫假設頂層值是一個純物件。)在該頂層物件中組織資料最常見的方式是進一步將資料分成子樹,其中每個頂層鍵代表一些相關資料的「網域」或「切片」。例如,一個基本的 Todo 應用程式的狀態可能如下所示

{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}

在此範例中,todosvisibilityFilter 都是狀態中的頂層鍵,每個都代表某個特定概念的資料「切片」。

大多數應用程式處理多種類型的資料,這些資料大致可分為三類

  • 網域資料:應用程式需要顯示、使用或修改的資料(例如「從伺服器擷取的所有 Todo」)
  • 應用程式狀態:特定於應用程式行為的資料(例如「Todo #5 目前已選取」,或「有一個正在進行的請求以擷取 Todo」)
  • UI 狀態:表示 UI 目前如何顯示的資料(例如「EditTodo 模式對話框目前已開啟」)

由於儲存體代表應用程式的核心,因此您應該根據您的網域資料和應用程式狀態定義您的狀態形狀,而不是您的 UI 組件樹。舉例來說,state.leftPane.todoList.todos 的形狀將是一個糟糕的想法,因為「todos」的想法是整個應用程式的核心,而不仅仅是 UI 的一部分。todos 切片應該位於狀態樹的頂端。

您的 UI 樹和您的狀態形狀很少會是一對一的對應。例外情況可能是您也在您的 Redux 儲存體中明確追蹤 UI 資料的各個方面,但即使如此,UI 資料的形狀和網域資料的形狀也可能不同。

一個典型的應用程式狀態形狀可能大致如下所示

{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}