核心概念
想象一下你的应用程序的状态被描述为一个普通对象。例如,一个待办事项应用程序的状态可能看起来像这样
{
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 来处理相应的 state keys。
function todoApp(state = {}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
}
}
这基本上就是 Redux 的全部思想。请注意,我们还没有使用任何 Redux API。它提供了一些实用程序来简化这种模式,但主要思想是,你描述了你的状态如何随着时间的推移响应动作对象而更新,而你编写的 90% 的代码只是纯 JavaScript,没有使用 Redux 本身、它的 API 或任何魔法。