这里先上一张redux的工作流程图, 便于理解下面代码

Redux 的工作流程

用一个简单对象来描述应用的状态。可以把Todo应用的状态如下描述:

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

这个对象看起来像“model”,但与“model”有一个重要的区别是禁止set操作。就是说在代码的不同部分不能随意更改状态——这种随意性往往会带来难以调试的bug。

如果要更改state需要派发一个Action。Action是一个用来描述应用变化情况的简单JavaScirpt对象(注意这里不存在任何魔术)。下面是几个Action的例子:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

强制规定将每一次变化都描述为一个Action对象,使得我们可以清晰的理解程序中发生变化的情况。对于这些变化,清晰的知道为什么变化。Action就像程序中发生变化情况的面包屑。 最后,再通过Reducer方法,将State和Action结合在一起。再次注意,这里不存在什么魔术事件,Reducer仅仅是一个普通方法,接收State和Action作为参数,并返回应用的下一个状态。 很难将一个庞大的应用状态都用一个方法来处理状态,可以将其拆分成若干个较小的方法组合来管理状态的各个部分:

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。Redux的API只是用来帮助实现该思想模式的一组工具方法,编码的关键是如何将随着时间变化的响应的状态描述为Action对象,90%的工作都是在编写简单JavaScript对象,这不会涉及到Redux本身,也不会涉及到它的API,更没有什么魔法。