核心概念

当使用普通对象来描述应用的 state 时。例如,todo 应用的 state 可能长这样:

  1. {
  2. todos: [{
  3. text: 'Eat food',
  4. completed: true
  5. }, {
  6. text: 'Exercise',
  7. completed: false
  8. }],
  9. visibilityFilter: 'SHOW_COMPLETED'
  10. }

这个对象就像 “Model”,区别是它并没有 setter(修改器方法)。因此其它的代码不能随意修改它,造成难以复现的 bug。

要想更新 state 中的数据,你需要发起一个 action。action 就是一个普通 JavaScript 对象(注意到没,这儿没有任何魔法?)用来描述发生了什么。下面是一些 action 的示例:

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

强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。 最终,为了把 action 和 state 串起来,开发一些函数,这就是 reducer。再次地,没有任何魔法,reducer 只是一个接收 state 和 action,并返回新的 state 的函数。 对于大的应用来说,不大可能仅仅只写一个这样的函数,所以我们编写很多小函数来分别管理 state 的一部分:

  1. function visibilityFilter(state = 'SHOW_ALL', action) {
  2. if (action.type === 'SET_VISIBILITY_FILTER') {
  3. return action.filter
  4. } else {
  5. return state
  6. }
  7. }
  8. function todos(state = [], action) {
  9. switch (action.type) {
  10. case 'ADD_TODO':
  11. return state.concat([{ text: action.text, completed: false }])
  12. case 'TOGGLE_TODO':
  13. return state.map((todo, index) =>
  14. action.index === index
  15. ? { text: todo.text, completed: !todo.completed }
  16. : todo
  17. )
  18. default:
  19. return state
  20. }
  21. }

再开发一个 reducer 调用这两个 reducer,进而来管理整个应用的 state:

  1. function todoApp(state = {}, action) {
  2. return {
  3. todos: todos(state.todos, action),
  4. visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  5. }
  6. }

这差不多就是 Redux 思想的全部。注意到没我们还没有使用任何 Redux 的 API。Redux 里有一些工具来简化这种模式,但是主要的想法是如何根据这些 action 对象来更新 state,而且 90% 的代码都是纯 JavaScript,没用 Redux、Redux API 和其它魔法。