核心概念
想像一下你的應用程式狀態被描述成一個純粹的物件。例如,待辦事項應用程式的狀態可能看起來像這樣
{
todos: [{
text: 'Eat food',
completed: true
}, {
text: 'Exercise',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
這個物件就像一個「模型」,只不過沒有設定器。這是為了讓程式碼的不同部分無法任意變更狀態,造成難以重現的錯誤。
若要變更狀態中的某個項目,你需要發送一個動作。動作是一個純粹的 JavaScript 物件(請注意我們沒有引入任何魔法),描述發生了什麼事。以下是幾個範例動作
{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }
強制規定每個變更都描述成一個動作,讓我們可以清楚了解應用程式中發生了什麼事。如果某個項目變更了,我們知道它為何變更。動作就像發生過什麼事的麵包屑。最後,為了將狀態和動作串連在一起,我們撰寫一個稱為「reducer」的函式。同樣地,它沒有任何魔法,只是一個函式,將狀態和動作作為引數,並傳回應用程式的下一個狀態。對於大型應用程式而言,撰寫這樣的函式會很困難,因此我們撰寫較小的函式來管理狀態的部分
function visibilityFilter(state = 'SHOW_ALL', action) {
if (action.type === 'SET_VISIBILITY_FILTER') {
return action.filter
} else {
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }])
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index
? { text: todo.text, completed: !todo.completed }
: todo
)
default:
return state
}
}
我們再寫一個 reducer,透過呼叫這兩個 reducer 來管理應用程式的完整狀態,以取得對應的狀態金鑰
function todoApp(state = {}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
}
}
這基本上是 Redux 的概念。請注意,我們尚未使用任何 Redux API。它附帶一些實用程式來簡化此模式,但主要概念是,你描述你的狀態如何隨著時間推移而更新,以回應動作物件,而你編寫的 90% 程式碼只是純粹的 JavaScript,不使用 Redux 本身、其 API 或任何魔法。