深入理解Redux之手写React-Redux

React-Redux主要由两部分组成,一是Provider(提供者),顾名思义作用就是提供状态数据。

另一部分是connect函数,它的作用是把UI组件和状态数据“连接”起来,实现了Model和View的分离,也就是UI组件并不直接管理状态数据,而是只负责界面的展示。

通过connect函数可以获得一个容器组件的创建器,进而创建出容器组件,而容器组件又包含了UI组件,由于容器组件是可以获取到状态数据的,获取到之后再传给UI组件就可以实现UI组件和状态数据的连接。

下面我们先来实现第一部分——Provider。

React-Redux库作用相当于是简化React对Redux的操作(因为Redux是独立于React的库,甚至也可以配合Vue.js等使用),因此React-Redux中的Provider并不直接拥有状态数据,

状态数据是在Redux中的。即Provider需要接收Redux中状态数据所在的store模块,才能获取到状态数据。如下:

<Provider store={store}>
  <App/>
</Provider>

我们刚才说了容器组件需要获取状态数据,而Provider是状态数据的提供者,因此Provider需要将状态数据传给容器组件。Provider的实现非常简单,如下。

export class Provider extends React.Component {

  static propTypes = {
    store: PropTypes.object.isRequired  // 声明接收Redux的store模块
  }

 // 声明要传给子组件(即容器组件)的数据名称(key)和数据类型
  static childContextTypes = {
    store: PropTypes.object
  }

 /* 指定上面的key对应的value */
  getChildContext () {
    return {
      store: this.props.store
    }
  }

  render() {
  // 渲染<Provider>的所有子组件,在本例中就是<App/>

    return this.props.children
  }
}

接下来实现connect函数,我们刚才说了connect会产生一个包装了UI组件的容器组件的创建器。而UI组件一方面负责界面的显示(读取状态数据),另一方面又要和用户交互,如监听按钮的点击事件,并执行某些操作(修改状态数据)。

因此UI组件需要拥有两类属性,一类我们叫做stateProps,即状态数据,UI组件会将状态数据渲染到界面上。另一类叫dispatchProps(即更新状态数据的方法),dispatch是redux中的概念,可以通过dispatch函数分发一个action(执行某个动作,进而修改状态数据)。

UI组件可以调用dispatchProps中的方法去间接地修改状态数据。

由于容器组件接收的是store,而store包含的是Redux全量的状态数据,而某个UI组件可能只需要整个应用中部分的状态数据,因此需要一个名为mapStateToProps的函数指定该UI组件需要哪些状态数据。

例如mapStateToProps=state=>({user:state.user}),这个函数就表明了该UI组件只需要状态数据中的user。

同理,在Redux中有actions的概念,它包含了所有的操作类型,而某个UI组件可能也只需要做一部分操作,因此需要一个名为mapDispatchToProps的对象指定该UI组件需要哪些操作类型。

mapDispatchToProps一般是如下格式(①)

格式①:{
    key1: actionCreator1,
    key2: actionCreator2
}

其中key是操作的名称,而后面的actionCreator是一个action的创建器,可以调用创建器产生action,进而通过dispatch方法分发该action。

我们最终要想获得dispatchProps,需要将其转换成如下这样的格式(②)。因为action的内容可能是变化的,比如我们要更新状态数据里面的user,需要产生一个对应的例如"updateUser"这样的action,显然我们在action中需要携带用户信息,不然怎么更新呢。因此

actionCreator是可以接收参数的,根据参数创建一个action。


格式②:
{
    key1:(...arguments)=>{

        dispatch(actionCreator1(...arguments))

    },

    key2:(...arguments)=>{

        dispatch(actionCreator2(...arguments))

    }
}

好了,准备知识都已经介绍完了,下面可以开始编写connect函数啦。

export function connect(mapStateToProps, mapDispatchToProps) {
// 接收两个参数,根据参数构造出UI组件所需的stateProps(状态数据)和dispatchProps(更新状态数据的方法)
//connect函数的返回值是一个ContainerComponentCreator,也就是容器组件的创建器,而我们说过容器组件会包装一个UI组件,因此创建器的方法参数是一个UI组件
  return (UIComponent) => {
    return class ContainerComponent extends React.Component {

      // 容器组件需要声明接收Provider提供的store
      static contextTypes = {
        store: PropTypes.object
      }

      constructor (props, context) {
        super(props)//调用父类构造器,不解释

     // 得到Provider传过来的store
        const store = context.store
        // 构造状态数据
        const stateProps = mapStateToProps(store.getState())
        // 将状态数据作为容器的state(因为状态改变意味着我们的UI组件需要随之变化,而state的改变正好会使得容器组件重新渲染)
        this.state = {...stateProps}

        //构造dispatchProps(更新状态数据的方法),这段不解释,请对照上面的格式①和格式②,很容易看出这段代码做了什么
        const dispatchProps = Object.keys(mapDispatchToProps).reduce((pre, key) => {
            const actionCreator = mapDispatchToProps[key]
            pre[key] = (...args) => store.dispatch(actionCreator(...args))
            return pre
        }, {})

        // 保存到组件上
        this.dispatchProps = dispatchProps
        // 绑定redux状态变化的监听
        store.subscribe(() => { // 状态变化的回调
          // 更新容器组件的状态,使容器组件重新渲染,进而导致UI组件的更新
          this.setState({...mapStateToProps(store.getState())})
        })
      }

      render () {
        // 渲染UI组件,并把UI组件所需的stateProps(状态数据)和dispatchProps(更新状态数据的方法)传入
        return <UIComponent  {...this.state} {...this.dispatchProps}/>
      }
    }

  }
}

原文地址:https://www.cnblogs.com/flamestudio/p/11993104.html

时间: 2024-10-09 11:00:20

深入理解Redux之手写React-Redux的相关文章

JDK动态代理深入理解分析并手写简易JDK动态代理(上)

原文引用https://www.dazhuanlan.com/2019/08/26/5d6300df6f20f/ 博客真的是好几个月没更了,2019新年第一篇,继续深入动态代理,前两篇简单分析了动态代理的实现原理之后,这次继续深入了解具体的实现方式,并手写一套简易的动态代理已加强理解: 本博客关于Java动态代理相关内容直达链接: JDK动态代理浅析 Cglib动态代理浅析 JDK动态代理深入理解分析并手写简易JDK动态代理(上) JDK动态代理深入理解分析并手写简易JDK动态代理(下) 博客真

React+Redux学习笔记:React+Redux简易开发步骤

前言 React+Redux 分为两部分: UI组件:即React组件,也叫用户自定义UI组件,用于渲染DOM 容器组件:即Redux逻辑,处理数据和业务逻辑,支持所有Redux API,参考之前的文章:Redux学习笔记:Redux简易开发步骤 而React+Redux是以上两部分结合起来,方便在React中使用Redux,专用库为React-Redux.js.React-Redux.js新增了一些新方法: Provider:容器跟组件,可直接把外部的state传递给所有子组件和UI组件: m

React深入 - 手写redux api

简介: 手写实现redux基础api createStore( )和store相关方法 api回顾: createStore(reducer, [preloadedState], enhancer) 创建一个 Redux store 来以存放应用中所有的 state reducer (Function): 接收两个参数,当前的 state 树/要处理的 action,返回新的 state 树 preloadedState: 初始时的 state enhancer (Function): stor

写了两篇文章,对于初学react+redux的人来说,很有好处

虽然官网的TodoList的例子写的很详细,但是都是一步到位,就是给你一个action,好家伙,全部都写好了,给你一个reducer,所有功能也是都写好了,但是我们这些小白怎么可能一下就消化那么多,那我们就来拆解,一步一步实现,试想我们开发程序也是一个一个功能区域实现,那么我们第一步就是先把整体结构构思出来,然后先把头部做出来,这样看是不是简单很多! 将持续更新react+redux 链接1:http://www.cnblogs.com/heigehe/articles/6237362.html

react + redux 完整的项目,同时写一下个人感悟

先附上项目源码地址和原文章地址:https://github.com/bailicangd... 做React需要会什么? react的功能其实很单一,主要负责渲染的功能,现有的框架,比如angular是一个大而全的框架,用了angular几乎就不需要用其他工具辅助配合,但是react不一样,他只负责ui渲染,想要做好一个项目,往往需要其他库和工具的配合,比如用redux来管理数据,react-router管理路由,react已经全面拥抱es6,所以es6也得掌握,webpack就算是不会配置也

【js】为什么要使用react+redux

前端的浪潮一叠叠袭来,带走了jQuery,带走了backbone,带来了react,带来了redux,但是面对层出不穷的前端技术,我们应该何去何从呢?近一年来笔者的也发生了同样的变化,技术栈从.net+backbone+requirejs+grunt变成了nodejs+react+webpack+gulp,一系列的变化也让笔者对整个过程,整个闭环的工具链有了一些自己的感受和理解,于是有了今天此文. 其实react出现得很早,但是笔者所在的唤作"大象转身"的大公司,所以内部技术的迭代,并

webpack+react+redux+es6

一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入门教程   redux middleware 详解   Redux研究 React 入门实例教程 webpack学习demo NPM 使用介绍 三.工程搭建 之前有写过 webpack+react+es6开发模式 ,文章里介绍了一些简单的配置,欢迎访问. 1.可以npm init, 创建一个新的工程

webpack+react+redux+es6开发模式

一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入门教程   redux middleware 详解   Redux研究 React 入门实例教程 webpack学习demo NPM 使用介绍 三.工程搭建 之前有写过 webpack+react+es6开发模式 ,文章里介绍了一些简单的配置,欢迎访问. 1.可以npm init, 创建一个新的工程

6周学习计划,攻克JavaScript难关(React/Redux/ES6 etc.)

6周学习计划,攻克JavaScript难关(React/Redux/ES6 etc.) 余博伦· 2 个月前 原文链接:A Study Plan To Cure JavaScript Fatigue 作者:Sacha Greif 和大家一样,最近我也看了Jose Aguinaga写的How it feels to learn JavaScript in 2016. 显然这篇文章击中了人们的痛处.它在Hacker News上排了不止一次第一.同样也是/r/javascript上最火的一篇,在Med