一、combineReducers:组合拆分状态的 Reducers
用逻辑逐渐复杂的时候,就要考虑将巨大的 Reducer 函数拆分成一个个独立的单元。 Reducers 在 Redux 中实际上是用来处理 Store 中存储的 State 中的某个部分,一个 Reducer 负责处理 State 中对应的那个属性。
1、应用
在实际项目中,可以在src 目录下新建 reducers 文件夹,在文件夹下建立各个模块的.js文件和index.js(组合文件),index.js用于构成最终的 rootReducer。
// todos.js
const initialTodoState = [];// 初始数据
const todos = (state = initialTodoState, action) => {};
export default todos;
// filter.js
const filter = (state = STRING, action) => {};
export default filter
// index.js
// 通过对象简洁表示法,将 todos 和 filter 作为对象属性合在一起,然后传递给 combineReducers 函数
// combineReducers 内部就会对 todos 和 filter 进行操作,然后生成类似我们之前的 rootReducer 形式
import { combineReducers } from "redux";
import todos from "./todos";
import filter from "./filter";
export default combineReducers({// combineReducers API用来组合多个小的 reducer
todos,
filter
});
2、combineReducers作用
- 组合所有 reducer 的 state,最后组合成类似我们之前定义的 initialState 对象状态树。
- 分发 dispatch 的 Action;通过 combineReducers 组合后,从 React 组件中 dispatch Action 会遍历检查各个模块,判断是否存在响应对应 action 的语句,如果存在,所有的这些语句都会响应。
二、容器组件 && 展示组件
为了将纯展示性的 React 组件和状态进一步抽离,Redux又提出“容器组件”和“展示组件”的概念。
1、概念
-
容器组件:在最终渲染界面的组件和 Store 中存储的 State 之间又加了一层,专门负责接收来自 Store 的 State,并把组件中想要发起的状态改变组装成 Action,然后通过 dispatch 函数发出。
-
展示组件:将状态彻底剥离之后剩下的那层,专门接收来自容器组件的数据,然后将其渲染成 UI 界面,并在需要改变状态时,告知容器组件,让其代为 dispatch Action。
2、应用
展示组件(包含App.js)存放在components文件夹,容器组件存放在containers文件夹;
App.js导入需要的容器组件,展示组件则由容器组件引入;
- App.js
class App extends React.Component {
render() {
return (
<div>
<AddTodoContainer />
<VisibleTodoList />
<Footer />
</div>
);
}
}
export default App;
- 容器组件:VisibleTodoList.js
import { connect } from "react-redux";
import { toggleTodo } from "../actions";
import TodoList from "../components/TodoList";
// 获取到来自 Redux Store 的 State 以及组件自身的原 Props,然后组合这两者成新的 Props,然后传给组件
const mapStateToProps = state => ({
todos: state.todos
});
// 定义所有需要 dispatch 的 Action 函数,并将其作为 Props 传给组件
const mapDispatchToProps = dispatch => ({
toggleTodo: id => dispatch(toggleTodo(id))
});
// 通过熟悉的 connect 函数接收 mapStateToProps 和 mapDispatchToProps 并调用,然后再接收 TodoList 组件并调用,返回最终的导出的容器组件。
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
- 展示组件:TodoList.js
import React from "react";
import PropTypes from "prop-types";
const TodoList = ({ todos, toggleTodo }) => (
<ul>
{todos.map(todo => (
<Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} />
))}
</ul>
);
// 检验
TodoList.propTypes = {
todos: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
completed: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired
}).isRequired
).isRequired,
toggleTodo: PropTypes.func.isRequired
};
export default TodoList;