详解关于react-redux中的connect用法介绍及原理解析


Posted in Javascript onSeptember 11, 2017

关于react-redux的一个流程图

详解关于react-redux中的connect用法介绍及原理解析

流程图

connect用法介绍

connect方法声明:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])

作用:连接React组件与 Redux store。

参数说明:

mapStateToProps(state, ownProps) : stateProps

这个函数允许我们将 store 中的数据作为 props 绑定到组件上。

const mapStateToProps = (state) => {
 return {
  count: state.count
 }
}

(1)这个函数的第一个参数就是 Redux 的 store,我们从中摘取了 count 属性。你不必将 state 中的数据原封不动地传入组件,可以根据 state 中的数据,动态地输出组件需要的(最小)属性。

(2)函数的第二个参数 ownProps,是组件自己的 props。有的时候,ownProps 也会对其产生影响。

当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的 stateProps,(在与 ownProps merge 后)更新给组件。

mapDispatchToProps(dispatch, ownProps): dispatchProps

connect 的第二个参数是 mapDispatchToProps,它的功能是,将 action 作为 props 绑定到组件上,也会成为 MyComp 的 props。

[mergeProps],[options]

不管是 stateProps 还是 dispatchProps,都需要和 ownProps merge 之后才会被赋给组件。connect 的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数,connect 就会使用 Object.assign 替代该方法。

[options] (Object) 如果指定这个参数,可以定制 connector 的行为。一般不用。

原理解析

首先connect之所以会成功,是因为Provider组件:

  1. 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
  2. 接收Redux的store作为props,通过context对象传递给子孙组件上的connect

那connect做了些什么呢?

它真正连接 Redux 和 React,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。

关于它的源码

connect是一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的Connect组件,该组件具有如下特点:

  1. 通过props.store获取祖先Component的store
  2. props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
  3. componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
  4. shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
  5. componentWillUnmount时移除注册的事件this.handleChange

由于connect的源码过长,我们只看主要逻辑:

export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
 return function wrapWithConnect(WrappedComponent) {
  class Connect extends Component {
   constructor(props, context) {
    // 从祖先Component处获得store
    this.store = props.store || context.store
    this.stateProps = computeStateProps(this.store, props)
    this.dispatchProps = computeDispatchProps(this.store, props)
    this.state = { storeState: null }
    // 对stateProps、dispatchProps、parentProps进行合并
    this.updateState()
   }
   shouldComponentUpdate(nextProps, nextState) {
    // 进行判断,当数据发生改变时,Component重新渲染
    if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
     this.updateState(nextProps)
      return true
     }
    }
    componentDidMount() {
     // 改变Component的state
     this.store.subscribe(() = {
      this.setState({
       storeState: this.store.getState()
      })
     })
    }
    render() {
     // 生成包裹组件Connect
     return (
      <WrappedComponent {...this.nextState} />
     )
    }
   }
   Connect.contextTypes = {
    store: storeShape
   }
   return Connect;
  }
 }

connect使用实例

这里我们写一个关于计数器使用的实例:

Component/Counter.js

import React, {Component} from 'react'

class Counter extends Component {
  render() {
    //从组件的props属性中导入四个方法和一个变量
    const {increment, decrement, counter} = this.props;
    //渲染组件,包括一个数字,四个按钮
    return (
      <p>
        Clicked: {counter} times
        {' '}
        <button onClick={increment}>+</button>
        {' '}
        <button onClick={decrement}>-</button>
        {' '}
      </p>
    )
  }
}

export default Counter;

Container/App.js

import { connect } from 'react-redux'
import Counter from '../components/Counter'
import actions from '../actions/counter';

//将state.counter绑定到props的counter
const mapStateToProps = (state) => {
  return {
    counter: state.counter
  }
};
//将action的所有方法绑定到props上
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    increment: (...args) => dispatch(actions.increment(...args)),
    decrement: (...args) => dispatch(actions.decrement(...args))
  }
};

//通过react-redux提供的connect方法将我们需要的state中的数据和actions中的方法绑定到props上
export default connect(mapStateToProps, mapDispatchToProps)(Counter)

完整代码

Github:https://github.com/lipeishang/react-redux-connect-demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript中的类继承
Nov 25 Javascript
jquery验证表单中的单选与多选实例
Aug 18 Javascript
我的Node.js学习之路(三)--node.js作用、回调、同步和异步代码 以及事件循环
Jul 06 Javascript
jQuery实现ToolTip元素定位显示功能示例
Nov 23 Javascript
JS实现重新加载当前页面
Nov 29 Javascript
Bootstrap超大屏幕的实现代码
Mar 22 Javascript
vue 使用自定义指令实现表单校验的方法
Aug 28 Javascript
详解使用angular框架离线你的应用(pwa指南)
Jan 31 Javascript
layer设置maxWidth及maxHeight解决方案
Jul 26 Javascript
小程序Request的另类用法详解
Aug 09 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
Jul 21 Javascript
vant中的toast轻提示实现代码
Nov 04 Javascript
详解使用Vue Router导航钩子与Vuex来实现后退状态保存
Sep 11 #Javascript
JS和jQuery通过this获取html标签中的属性值(实例代码)
Sep 11 #jQuery
详解webpack2+React 实例demo
Sep 11 #Javascript
react-native 完整实现登录功能的示例代码
Sep 11 #Javascript
Layui table 组件的使用之初始化加载数据、数据刷新表格、传参数
Sep 11 #Javascript
Vuejs 页面的区域化与组件封装的实现
Sep 11 #Javascript
js封装成插件的步骤方法
Sep 11 #Javascript
You might like
使用XDebug调试及单元测试覆盖率分析
2011/01/27 PHP
Yii Framework框架获取分类下面的所有子类方法
2014/06/20 PHP
Yii快速入门经典教程
2015/12/28 PHP
PHP Cli 模式设置进程名称的方法
2019/06/12 PHP
PHP ob缓存以及ob函数原理实例解析
2020/11/13 PHP
javascript基础的动画教程,直观易懂
2007/01/10 Javascript
Jquery 基础学习笔记
2009/05/29 Javascript
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
Jquery图片滚动与幻灯片的实例代码
2013/04/08 Javascript
JS实现遮罩层效果的简单实例
2013/11/12 Javascript
JS中自定义定时器让它在某一时刻执行
2014/09/02 Javascript
jQuery/CSS3图片特效插件整理推荐
2014/12/07 Javascript
Javascript 拖拽雏形(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
《JavaScript函数式编程》读后感
2015/08/07 Javascript
jquery实现的Accordion折叠面板效果代码
2015/09/02 Javascript
JavaScript判断按钮被点击的方法
2015/12/13 Javascript
针对JavaScript中this指向的简单理解
2016/08/26 Javascript
scroll事件实现监控滚动条并分页显示(zepto.js)
2016/12/18 Javascript
解决Angular.Js与Django标签冲突的方案
2016/12/20 Javascript
vue+vuex+json-seiver实现数据展示+分页功能
2019/04/11 Javascript
JS实现秒杀倒计时特效
2020/01/02 Javascript
[51:07]VGJ.S vs Pain 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
python多线程编程方式分析示例详解
2013/12/06 Python
python完成FizzBuzzWhizz问题(拉勾网面试题)示例
2014/05/05 Python
Python中使用Inotify监控文件实例
2015/02/14 Python
详解Python 数据库 (sqlite3)应用
2016/12/07 Python
使用Python实现租车计费系统的两种方法
2018/09/29 Python
python利用插值法对折线进行平滑曲线处理
2018/12/25 Python
Python中使用遍历在列表中添加字典遇到的坑
2019/02/27 Python
Pytorch根据layers的name冻结训练方式
2020/01/06 Python
如何用Java实现列出某个目录下的所有子目录
2015/07/20 面试题
优秀的毕业生的自我评价
2013/12/12 职场文书
2014年母亲节寄语
2014/05/07 职场文书
公务员试用期满考核材料
2014/05/22 职场文书
聘用合同范本
2015/09/21 职场文书
智慧人生:永远不需要向任何人解释你自己
2019/08/20 职场文书