资讯专栏INFORMATION COLUMN

快速理解react-redux

MoAir / 3339人阅读

摘要:和的结合简述相信很多前端开发者都听说或使用过,我曾写过一篇关于快速理解的文章,虽说是快速理解,但实际上更应该叫做复习吧。它通过高阶函数,纯函数使我们在编写组件时完全不用接触相关内容,只通过将组件和数据连接起来即可。

react-redux react和redux的结合 简述

相信很多前端开发者都听说或使用过react-redux,我曾写过一篇关于快速理解redux的文章,虽说是快速理解,但实际上更应该叫做复习redux吧。本文也只是讲述react-redux的思想及原理,对于细节实现则不赘述。

一、初始化工程

我们先create-react-app新建一个react项目,然后安装第三方库cnpm install --save prop-types

我们在src目录下新建3个文件,Header.js、Content.js、ThemeSwitch.js

组件结构是这样的

运行起来是这样的

二、结合context和store

我们先构建store,并且把它放在Index组件的context里面,那样Index以下的所有组件都可以使用store了。

  class Index extends Component {
  static childContextTypes = {
    store: PropTypes.object
  }

  getChildContext () {
    return { store }
  }

  render () {
    return (
      
) } }

我们修改Header,Content,ThemeSwitch,定义一个函_updateThemeColor在componentWillMount中调用

在该函数中获取Index组件context里的store,并且将store里的colorState这只为自己文本的颜色

我们再修改ThemeSwitch,使按钮绑定事件,点击后执行dispatch修改store里的state

此时我们点击按钮后,store里的数据确实改变了,可是页面却没有改变,为何?

因为我们忽略了subscribe,使得dispatch后_updateThemeColor函数并未执行

我们分别给 Header.js、Content.js、ThemeSwitch.js 的 componentWillMount 生命周期都加上监听数据变化重新渲染的代码

代码如下,仅以ThemeSwitch为例,其他文件类似

class ThemeSwitch extends Component {
  static contextTypes = {
    store: PropTypes.object
  }

  constructor () {
    super()
    this.state = { themeColor: "" }
  }

  componentWillMount () {
    const { store } = this.context
    this._updateThemeColor()
    store.subscribe(() => this._updateThemeColor())
  }

  _updateThemeColor () {
    const { store } = this.context
    const state = store.getState()
    this.setState({ themeColor: state.themeColor })
  }

  // dispatch action 去改变颜色
  handleSwitchColor (color) {
    const { store } = this.context
    store.dispatch({
      type: "CHANGE_COLOR",
      themeColor: color
    })
  }

  render () {
    return (
      
) } }

到这里,我们已经把react-redux的骨架搭建起来了

三、connect 和 mapStateToProps

我们观察刚刚写的组件,他们存在两个问题

有大量重复逻辑

使用Connect高阶组件解决

对context依赖过强,可复用性过低

使用mapStateToProps解决

使用高阶组件

我们需要高阶组件帮助我们从 context 取数据,我们也需要写 Dumb(纯) 组件帮助我们提高组件的复用性。所以我们尽量多地写 Dumb 组件,然后用高阶组件把它们包装一层,高阶组件和 context 打交道,把里面数据取出来通过 props 传给 Dumb 组件。

这个高阶组件被其铭文Connect,因为他可以把 Dunb组件context数据 connect 起来

import React, { Component } from "react"
import PropTypes from "prop-types"

export const connect = (mapStateToProps) => (WrappedComponent) => {
  class Connect extends Component {
    static contextTypes = {
      store: PropTypes.object
    }

    render () {
      const { store } = this.context
      let stateProps = mapStateToProps(store.getState())
      // {...stateProps} 意思是把这个对象里面的属性全部通过 `props` 方式传递进去
      return 
    }
  }

  return Connect
}

我们将新建一个react-redux文件,将Connect放进去
我们在定义 mapStateToProps函数 使它接收某参数,返回相应的数据。因为不同的组件需要store中不同的数据

import React, { Component } from "react"
import PropTypes from "prop-types"
import { connect } from "./react-redux"

class Header extends Component {
  static propTypes = {
    themeColor: PropTypes.string
  }

  render () {
    return (
      

React.js 小书

) } } const mapStateToProps = (state) => { return { themeColor: state.themeColor } } Header = connect(mapStateToProps)(Header) export default Header

此时,Header 删掉了大部分关于 context 的代码,它除了 props 什么也不依赖,它是一个 Pure Component,然后通过 connect 取得数据。我们不需要知道 connect 是怎么和 context 打交道的,只要传一个 mapStateToProps 告诉它应该怎么取数据就可以了。
此时,Connect还未能监听渲染,我们需要在Connect中创建渲染函数并且在componentWillMount中添加渲染函数

  export const connect = (mapStateToProps) => (WrappedComponent) => {
  class Connect extends Component {
    static contextTypes = {
      store: PropTypes.object
    }

    constructor () {
      super()
      this.state = { allProps: {} }
    }

    componentWillMount () {
      const { store } = this.context
      this._updateProps()
      store.subscribe(() => this._updateProps())
    }

    _updateProps () {
      const { store } = this.context
      let stateProps = mapStateToProps(store.getState(), this.props) // 额外传入 props,让获取数据更加灵活方便
      this.setState({
        allProps: { // 整合普通的 props 和从 state 生成的 props
          ...stateProps,
          ...this.props
        }
      })
    }

    render () {
      return 
    }
  }

  return Connect
}

现在已经很不错了,Header.js 和 Content.js 的代码都大大减少了,并且这两个组件 connect 之前都是 Dumb 组件。接下来会继续重构 ThemeSwitch。

mapDispatchToProps

到目前为止,我们每次在更改数据时,都要用过store.dispatch修改。
为了使组件更 Dunb(纯) 我们对Connect和ThemeSwitch增加一个mapDispatchToProps 函数,使ThemeSwitch组件摆脱对store.dispatch的依赖

export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {
  class Connect extends Component {
    static contextTypes = {
      store: PropTypes.object
    }

    constructor () {
      super()
      this.state = {
        allProps: {}
      }
    }

    componentWillMount () {
      const { store } = this.context
      this._updateProps()
      store.subscribe(() => this._updateProps())
    }

    _updateProps () {
      const { store } = this.context
      let stateProps = mapStateToProps
        ? mapStateToProps(store.getState(), this.props)
        : {} // 防止 mapStateToProps 没有传入
      let dispatchProps = mapDispatchToProps
        ? mapDispatchToProps(store.dispatch, this.props)
        : {} // 防止 mapDispatchToProps 没有传入
      this.setState({
        allProps: {
          ...stateProps,
          ...dispatchProps,
          ...this.props
        }
      })
    }

    render () {
      return 
    }
  }
  return Connect
}
import React, { Component } from "react"
import PropTypes from "prop-types"
import { connect } from "./react-redux"

class ThemeSwitch extends Component {
  static propTypes = {
    themeColor: PropTypes.string,
    onSwitchColor: PropTypes.func
  }

  handleSwitchColor (color) {
    if (this.props.onSwitchColor) {
      this.props.onSwitchColor(color)
    }
  }

  render () {
    return (
      
) } } const mapStateToProps = (state) => { return { themeColor: state.themeColor } } const mapDispatchToProps = (dispatch) => { return { onSwitchColor: (color) => { dispatch({ type: "CHANGE_COLOR", themeColor: color }) } } } ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch) export default ThemeSwitch

光看 ThemeSwitch 内部,是非常清爽干净的,只依赖外界传进来的 themeColor 和 onSwitchColor。但是 ThemeSwitch 内部并不知道这两个参数其实都是我们去 store 里面取的,它是 Dumb 的。

五、Provider

我们要把所有和context有关的东西都分离出去,现在只有Index组件是被污染的
所以,我们在react-redux中新增Provider类,让它包裹成为Index的高阶函数,包裹index
使组件结构图如下

代码如下

export class Provider extends Component {
  static propTypes = {
    store: PropTypes.object,
    children: PropTypes.any
  }

  static childContextTypes = {
    store: PropTypes.object
  }

  getChildContext () {
    return {
      store: this.props.store
    }
  }

  render () {
    return (
      
{this.props.children}
) } }
...
// 头部引入 Provider
import { Provider } from "./react-redux"
...

// 删除 Index 里面所有关于 context 的代码
class Index extends Component {
  render () {
    return (
      
) } } // 把 Provider 作为组件树的根节点 ReactDOM.render( , document.getElementById("root") )

此时,我们就把所有关于 context 的代码从组件里面删除了。

六、react-redux总结

redux的思想就是有条理地,有规则地修改共享数据。而react里刚好有 context 这个东西可以被某组件以下的所有组件共享,为了在react中优雅的修改context,react-redux就诞生了。它通过高阶函数(Connect),纯函数(mapStateToProps, mapDispatchToProps) 使我们在编写组件时完全不用接触context相关内容,只通过ConnectDumb组件Context数据 连接起来即可。

参考

react小书

完整代码

make-react-redux

本文如果有错,欢迎指出

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100241.html

相关文章

  • react-redux 开发实践与学习分享

    摘要:简介是一个状态管理的库,由基础上开发出来,与的主要区别是只有一个,关于,后文会详述。这个函数接受四个参数,它们分别是,,和。之前在注册页面,如果没有满足相关条件,则触发的行为。具体定义了项目中触发的行为类别,通过属性来区别于不同的行为。 redux简介 redux是一个js状态管理的库,由flux基础上开发出来,与flux的主要区别是只有一个store,关于store,后文会详述。在各...

    imccl 评论0 收藏0
  • React-Redux 中文文档

    摘要:介绍快速开始是的官方绑定库。通常你可以以下面这种方式调用方法基础教程为了进一步了解如何实际使用,我们将一步一步创建一个一个实例跳转到 介绍 快速开始 React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据 安装 在你的React app中使用React-Redux: npm i...

    MobService 评论0 收藏0
  • react-redux初探理解

    摘要:它的作用就是像它的名字那样,建立一个从外部的对象到组件的对象的映射关系。比如表示从整个的表示当前组件容器的用来建立组件的参数到方法的映射比如表示它定义了哪些用户的操作应该当作,传给。 最近做的项目加入了react-redux,对react-redux一直没理解透彻,最近有时间把react-redux梳理了一番,希望能够帮助到大家, 首先有这几个文件,action,reducer,sag...

    ziwenxie 评论0 收藏0
  • React专题:react,redux以及react-redux常见一些面试题

    摘要:我们可以为元素添加属性然后在回调函数中接受该元素在树中的句柄,该值会作为回调函数的第一个参数返回。使用最常见的用法就是传入一个对象。单向数据流,比较有序,有便于管理,它随着视图库的开发而被概念化。 面试中问框架,经常会问到一些原理性的东西,明明一直在用,也知道怎么用, 但面试时却答不上来,也是挺尴尬的,就干脆把react相关的问题查了下资料,再按自己的理解整理了下这些答案。 reac...

    darcrand 评论0 收藏0
  • React-redux中connect方法的理解

    摘要:应用中唯一的状态应用的子组件例子方法来看下函数到底是如何将和组件联系在一起的,注意到文档中有这样的一句话并不会改变它连接的组件,而是提供一个经过包裹的组件。 关于React-redux Redux是React全家桶的重要一员,之前在知乎上也看到类似的提问:该如何通俗易懂的理解Redux? Redux是JavaScript的状态容器,Redux的概念简单明了: 1. 应用中所有的状...

    Bryan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<