React 状态——Redux(下)

165 阅读2分钟

一、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;