状态树设计

状态组织

数据流

数据流角度的组件协同

Redux 应用中数据的生命周期遵循下面 4 个步骤:

  • 使用 store.dispatch(action) 分发消息

action 就是一个描述发生了什么的普通对象。比如:

{ type: 'LIKE_ARTICLE', articleId: 42 };
{ type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Megan' } };
{ type: 'ADD_TODO', text: 'Read the Redux docs.'};

可以把 action 理解成新闻的摘要。如 “玛丽喜欢 42 号文章。” 或者 “任务列表里添加了’学习 Redux 文档’”。你可以在任何地方调用 store.dispatch(action),包括组件中、XHR 回调中、甚至定时器中。

  • Redux store 调用传入的 reducer 函数

Store 会把两个参数传入 reducer 当前的 state 树和 action。例如,在这个 todo 应用中,根 reducer 可能接收这样的数据:

// 当前应用的 state(todos 列表和选中的过滤器)
let previousState = {
  visibleTodoFilter: "SHOW_ALL",
  todos: [
    {
      text: "Read the docs.",
      complete: false,
    },
  ],
};

// 将要执行的 action(添加一个 todo)
let action = {
  type: "ADD_TODO",
  text: "Understand the flow.",
};

// render 返回处理后的应用状态
let nextState = todoApp(previousState, action);

注意 reducer 是纯函数。它仅仅用于计算下一个 state。它应该是完全可预测的:多次传入相同的输入必须产生相同的输出。它不应做有副作用的操作,如 API 调用或路由跳转。这些应该在 dispatch action 前发生。

  • 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。

根 reducer 的结构完全由你决定。Redux 原生提供 combineReducers() 辅助函数,来把根 reducer 拆分成多个函数,用于分别处理 state 树的一个分支。

下面演示 combineReducers() 如何使用。假如你有一个 todos 列表,使用当前的选择过滤器来追踪两个 reducers(原文:and the currently selected filter setting to keep track of with two reducers):

function todos(state = [], action) {
  // 省略处理逻辑...
  return nextState;
}

function visibleTodoFilter(state = "SHOW_ALL", action) {
  // 省略处理逻辑...
  return nextState;
}

let todoApp = combineReducers({
  todos,
  visibleTodoFilter,
});

当你触发 action 后,combineReducers 返回的 todoApp 会负责调用两个 reducer:

let nextTodos = todos(state.todos, action);
let nextVisibleTodoFilter = visibleTodoFilter(state.visibleTodoFilter, action);

然后会把两个结果集合并成一个 state 树:

return {
  todos: nextTodos,
  visibleTodoFilter: nextVisibleTodoFilter,
};

虽然 combineReducers() 是一个很方便的辅助工具,你也可以选择不用;你可以自行实现自己的根 reducer!

  • Redux store 保存了根 reducer 返回的完整 state 树。

这个新的树就是应用的下一个 state 所有订阅 store.subscribe(listener) 的监听器都将被调用;监听器里可以调用 store.getState() 获得当前 state。现在,可以应用新的 state 来更新 UI。如果你使用了 React Redux 这类的绑定库,这时就应该调用 component.setState(newState) 来更新。

Links

上一页