❓ state 过于庞大怎么办
因为 Redux 应用中只有一个 store,因此,当应用的交互越来越复杂时,store 必定会变成一个非常庞大的对象。这时,我们可以使用 Redux 提供的 combineReducers()
方法将多个小的 reducer 组合成一个 rootReducer,而每个小的 reducer 只关心自己负责的 action.type
,因为在整个应用中,有些 state 之间是互不关联的,因此我们可以拆分 reducer,不同的 reducer 处理不同的 action.type
。
假设现在有两个逻辑:一个计数器和一个 TODO。很明显这两个逻辑之间没有任何的联系,因此我们可以拆分成两个 reducer,然后再组合起来传给 createStore()
:
// 计数器 reducer
function counter(state = 0, action) {
switch(action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state -1;
default:
return state;
}
}
// TODO reducer
function todos(state = [], action) {
switch(action.type) {
case 'ADD_TODO':
return state.concat([action.text]);
default :
return state;
}
}
// 组合成一个 rootReducer
const rootReducer = combineReducers({
counter,
todos
});
// 根据 rootReducer 创建 store
const store = createStore(rootReducer)
console.log(store.getState());
结果
可以看到,store.getState()
中的 key 变成了子 reducer 的函数名,达到了拆分之间没有联系的 state 的目的。而 key 变成了子 reducer 的函数名的原因是,在组合 reducer 时的写法:
// 组合成一个 rootReducer
const rootReducer = combineReducers({
counter,
todos
});
这里传入给 combineReducers()
方法的是一个对象,这里使用了 ES6 的语法,即当对象的 key 和 value 同名时,可以省略 key,上面的写法相当于:
const rootReducer = combineReducers({
- counter,
+ counter: counter,
- todos
+ todos: todos
});
当然,key 是可以随意修改的,只是修改后,对于 state 的 key 也会有所不同罢了。需要记住的是 combineReducers()
方法的参数是一个对象,对象的 value 是需要组合的 reducer,对象的key 对应的是 state 中的 key,返回的是一个组合后的 reducer 函数,可以像普通 reducer 一样传给 createStore()
方法创建 store。
与 React 结合后结果是这样的:
在 coding 之前
构建一个 Redux 应用之前,我们应该先搭建好架构,也就是设计模式的那一套东西,在 coding 之前,不妨先停下来思考一下:
-
代码文件的组织结构
- 按角色组织
- 按功能组织
-
state 树的设计
- 一个模块控制一个 state 节点
- 避免冗余数据:做到 state 的范式化,类似 SQL 关系型数据库。为解决范式化数据的性能问题,可以使用 reselect 这样的工具提高性能。
- 树形结构扁平,避免很深的层次
- 确定模块的边界:在理想情况下,我们应该通过增加代码就能增加功能,而不是修改现有的代码。
下面是一个按功能组织的文件结构:
todoList/
action.js # 定义 action creators
actionTypes.js # 定义 action 类型
index.js # 把这个功能模块的文件导入,然后统一导出
reducer.js # 定义 reducer 如何处理 action
views/ # 定义所有 React 组件,包括容器组件和展示组件
component.js
container.js
filter/
action.js
actionTypes.js
index.js
reducer.js
views/
component.js
container.js
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。