欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

自定义React-redux

程序员文章站 2022-03-21 16:37:55
实现mini版react redux 1. 理解react redux模块 1). react redux模块整体是一个对象模块 2). 包含2个重要属性: Provider和connect 3). Provider 值: 组件类 作用: 向所有容器子组件提供全局store对象 使用: 4). co ......

实现mini版react-redux

1. 理解react-redux模块

 1). react-redux模块整体是一个对象模块
 2). 包含2个重要属性: provider和connect
 3). provider
    值: 组件类
    作用: 向所有容器子组件提供全局store对象
    使用: <provider store={store}><xxx/></provider>
 4). connect
    值: 高阶函数
    作用: 包装组件生成容器组件, 让被包装组件能与redux进行通信
    使用: connect(mapstatetoprops, mapdispatchtoprops)(xxx)
 

2. context的理解和使用

1). 理解
  当你觉得多层传递props麻烦, 可以选择使用context
  context是组件对象的一个属性, 它的值是一个对象
  一个组件指定的context内数据, 所有层次子组件都可以读取到
  如果可以尽量不用context, 你可以选择使用react-redux, react-redux内部就利用了context
2). 使用
  父组件:
      static childcontexttypes = {
        color: proptypes.string
      }
      getchildcontext() {
        return {color: 'red'};
      }
  后代组件:
      static contexttypes = {
        color: proptypes.string
      }
      
      render () {
        this.context.color
      }

3. 实现代码: src/libs/react-redux/index.js

import react, {component} from 'react'
import proptypes from 'prop-types'

/*
1. provider组件类
 */
export class provider extends component {
  // 声明当前组件接收store
  static proptypes = {
    store: proptypes.object.isrequired
  }

  // 必须声明向子节点指定全局数据store
  static childcontexttypes = {
    store: proptypes.object.isrequired
  }

  // 指定向子组件指定全局数据store
  getchildcontext() {
    return {store: this.props.store};
  }

  render() {
    // 返回所有子节点(如果没有子节点返回undefined, 如果只有一个子节点它是对象, 如果有多个它是数组)
    return this.props.children
  }
}

/*
2. connect方法
 */
export function connect(mapstatetoprops = () => null, mapdispatchtoprops = {}) {
  // 返回函数(接收被包装组件类作为参数)
  return (wrapcomponent) => {
    // 返回一个新的组件类
    return class connectcomponent extends component {
      // 声明接收全局store
      static contexttypes = {
        store: proptypes.object.isrequired
      }

      // 构造函数的第2个参数为context对象
      constructor(props, context) {
        super(props)
        console.log('constructor', this.context) // 此时组件对象中还没有context
        // 从context中取出store
        const {store} = context
        // 一般属性: 调用mapstatetoprops函数得到包含所有需要传递一般属性的集合对象
        const stateprops = mapstatetoprops(store.getstate())
        // 分发action的函数属性: 调用自定义的整合函数生成包含多个分发action的函数的对象
        const dispatchprops = this.bindactioncreators(mapdispatchtoprops)

        // 初始化状态, 包含所有需要传递给wrapcomponent组件的一般属性
        this.state = {
          ...stateprops
        }
        // 将包含dispatch函数的对象保存在组件对象上(不用放到state中)
        this.dispatchprops = dispatchprops
      }

      /*
      根据包含多个action creator的对象, 返回一个包含多个分发action的函数的对象
       */
      bindactioncreators = (mapdispatchtoprops) => {
        // 准备一个保存分发action函数的对象容器
        const dispatchprops = {}
        // 遍历每个action creator
        object.keys(mapdispatchtoprops).foreach((key) => {
          // 得到某个action creator
          const actioncreator = mapdispatchtoprops[key]
          //定义包含分发action代码的函数, 并只在到准备好的容器中
          dispatchprops[key] = (...args) => {
            this.context.store.dispatch(actioncreator(...args))
          }
        })
        // 返回dispatch代码函数容器对象
        return dispatchprops
      }

      componentdidmount() {
        console.log('componentdidmount', this.constructor)
        // 得到store
        const {store} = this.context
        // 订阅监听
        store.subscribe(() => {
          // 一旦store中的state有变化, 更新组件状态, 从而导致被包装组件重新渲染
          this.setstate(mapstatetoprops(store.getstate()))
        })
      }

      render() {
        return <wrapcomponent {...this.state} {...this.dispatchprops} />
      }
    }
  }
}