React-Redux 数据流转详解

1. 前言

    刚从 Vue+ElementUI 转来 React+BlueUI 着实有些被 React 前端数据流转给秀了;前端请求后端服务,服务响应返回数据,前端拿着数据渲染到 UI,这么简单的流程,到了 React 就被 action、reducer、store、和 state、props 数据传递给带进了胡同里。

2. Redux 单向数据流转特性

    严格的单向数据流是 Redux 架构的设计核⼼
    Redux 应⽤中数据的⽣命周期遵循下⾯ 4 个步骤:

  • 调用 store.dispatch(action)
  • Redux store 调用传入的 reducer 函数
  • 根 reducer 把多个子 reducer 输出合并为一个状态树 state 树
  • Redux 保存了根 reducer 返回的完整 state 树

2.1 Store 存储唯一的 State

    Store 就是⽤来维持应⽤所有的 state tree 的⼀个对象。改变 store 内 state 的唯⼀途径是对它 dispatch ⼀个 action。
    Middleware 是包装 store 下 dispatch() 的⾼阶函数,返回⼀个新的 dispatch 函数;redux-thunk 或 redux-promise ⽀持异步 actions 的 middleware;
    Store 保存了根 Reducer 返回的完整 State 树,所有订阅 store.subscribe(listener) 的监听器都将被调⽤;监听器⾥可以调⽤ store.getState() 获得当前 state。拿到新的 state 来重新渲染更新 UI。

eg: 优惠券 store.js 伪代码

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';

const createStoreWithMdware = applyMiddleware(
  thunkMiddleware
)(createStore);

export default createStoreWithMdware;

2.2 Action 触发改变 State

    Action 是一个对象,表明要改变 state;可以在任何地⽅调⽤ store.dispatch(action) 来触发改变 state。
    如下定义一个 action,获取后端服务优惠券列表的动作;一般 action 包含 type 和 data 属性,用来 type 标识不同的 action 对象,data 是待处理放入 state 树的数据。

eg: 优惠券活动 action.js 伪代码

export function getMarketingCouponList(params) {
  return (dispatch) => {
    ajax({
        api: 'http://localhost:8080/coupon/findCouponActivityListByPage',
        method: 'post',
        data: params
      }, (json) => {
        dispatch({
          type: 'GET_LIST_SUCCESS',
          data: json.data
        });
      }, (json) => {
        dispatch({
          type: 'GET_LIST_FAILED',
          data: json
        });
      });
  };
}

2.3 Reducer 返回新的 State

    Reducer 函数接受两个参数,当前 state 树和 action(包含待放入 state 的数据);
    根 reducer 把多个子 reducer 输出合并为一个状态树 state 树

eg: 优惠券活动 reducer.js(marketingCoupon.js) 伪代码

const initialState = {
  // 优惠券活动数据
  activityData: [],
  couponData: []
};
const defaultAction = {
  type: 'doNothing'
};
// reducer 处理 (state, action)
export default function index(state = initialState, action = defaultAction) {
  switch (action.type) {
    case 'GET_LIST_SUCCESS':
      return Object.assign({}, state, {
        listLoading: false,
        activityData: action.data
      });
    default:
      return state;
  }
}

eg:根rootReducer.js

import { routerReducer } from 'react-router-redux';
import { combineReducers } from 'redux';
import marketingCoupon from './marketingCoupon/';

// 将现有的reduces加上路由的reducer
const rootReducer = combineReducers({
    marketingCoupon,
  routing: routerReducer
});
export default rootReducer;

3. react-redux

3.1 安装 React-redux 库

npm install --save react-redux

3.2 搭配 React 使用

    Redux 要支持 React 需要安装 react-redux 库;Redux 的 React 绑定库是基于 容器组件和展示组件相分离的。
    你可以直接使⽤ store.subscribe() 来编写容器组件;建议使用 React Redux 库的 connect() ⽅法来⽣成,⽅法做了性能优化来避免很多不必要的重复渲染。
    connect() ⽅法有两个主要的参数,⽽且都是可选的。第⼀个参数 mapStateToProps 是个函数,让你在数据变化时从 store 获取数据,并作为 props 传到组件中。第⼆个参数 mapDispatchToProps 依然是函数,让你可以 使⽤ store 的 dispatch ⽅法,通常都是创建 action 创建函数并预先绑定, 那么在调⽤时就能直接分发 action。
    在执⾏ connect() 时没有指定 mapDispatchToProps ⽅法,React Redux 默认将 dispatch 作为 prop 传⼊。

3.3 “优惠券活动“伪代码

eg: 优惠券活动页面 couponActivity.jsx 伪代码

import React from 'react';
import { connect } from 'react-redux';
// 定义 action 对象的 action.js
import * as actions from '../../actions/marketingCoupon';

class MarketingCoupon extends React.Component {
  constructor(props) {
    super(props);
    this.state={};
    this.field = new Field(this);
  }
  // 进入页面加载
  componentDidMount(){
    window.onSearchMarketingCoupon=this.onSearch.bind(this);
    this.onSearch(1);
  }
  pageChange=(value)=> {
    this.onSearch(value);
  };
  //查询列表
  onSearch(pageIndex){
    const { dispatch } = this.props;
    let params= {
      page:pageIndex,
      pageSize:10,
      activityName:this.state.filterActivityName
    };
    dispatch(actions.getMarketingCouponList(params));
  }
  // 表格数据自定义渲染 end
  render() {
    return (
    <div>
      <div>
        <div>
          <Table dataSource={this.props.data.activityData.list} primaryKey="activityId" isLoading = {this.state.listLoading}  hasBorder={false} >
            <Table.Column title="活动名称" dataIndex="activityName"/>
            <Table.Column title="创建时间" dataIndex="createTime" style={{textAlign: 'center', width: '150px'}}/>
          </Table>
        </div>
        <div className="page">
          <Pagination defaultCurrent={this.props.data.activityData.pageNumber} pageSize={this.props.data.activityData.pageSize} total={this.props.data.activityData.totalRow} onChange={this.pageChange.bind(this)}/>
        </div>
      </div>
    </div>
    );
  }
}
export default connect((state) => {
  return {
    data:state.marketingCoupon
  };
})(MarketingCoupon);

3.4 “优惠券活动“数据流转

(1)store 存储着唯一的 state 树;
(2)进入页面,触发 onSearch() 方法来查询优惠券列表,ajax 请求后端服务获取响应结果集;
(3)此处使用 connect() 生成容器组件,从 props 中拿到 dispatch,通过 dispatch 派发一个 action 对象(参考 action.js);
(4)reducer 函数处理当前 state tree 和 action.data 返回新的 state 树(参考 reducer.js);
(5)通过 connect() 获取新的 state 树,渲染数据,props 的数据更新相应的 UI(参考 couponActivity.jsx);

扩展:
容器组件和展示组件
简单来说,展示组件就是普通的 React 组件,比如 Button,Dialog。容器组件就是就是使⽤ store.subscribe() 从 Redux state 树中读取部分数据,并通过 props 来把这些数据提供给要渲染的组件。可以把展示组件和 Redux 关联起来。

展示组件 容器组件
说明 描述如何展现 描述如何运行
数据来源 props state
数据修改 调用props中的回调函数 store.dispatch(action)
功能 (1)读取 State;(2)派发 Action;(3)定义 mapDispatchToProps() 方法接收 dispatch() 方法,注入到 props 的回调方法,供展示组件使用 props.dispatch()

上一篇:Redux 词汇,不巧你也不熟
Power By niaonao, The End

发布了132 篇原创文章 · 获赞 312 · 访问量 100万+

猜你喜欢

转载自blog.csdn.net/niaonao/article/details/105725908
今日推荐