react dispatch_React-Redux4学习笔记

6a4e82897ef6727cfa89c004af58f4b8.png

说明:此篇作为ARTS学习打卡专用(何为ARTS,详见这里),每周输出一篇原创能力有限,但是自己不想说放弃这个 flag,所以以下内容可能存在(但不限于)如下问题: 1. 篇幅短小。 2. 解释不够详尽。 3. 内容不够严谨。 4. 措辞未经修饰。

目的

学习下 redux 如何通过 store 来驱动更新 react 组件,及其优化方式。以下是基于react-redux4.4.10。

React-Redux 实现思路

如何让组件知道 state 更新

基本思路是通过把 store 注入到 context 里面让所有组件都有机会通过 context 获取到 store,并订阅 state 的变化。我们看下 Provider 实现:

class Provider extends React.Component {
  getChildContext() {
    return {
      store: this.store
    }
  }
  constructor( props ) {
    super( props );
    this.store = props.store
  }

  render() {
    return Children.only( this.props.children );
  }
}

然后通过 connect 给组件外层包一层 hoc,在这个 hoc 中订阅 state 的变化,示例代码:

function connect( mapStateToProps, mapDispatchToProps, mergeProps, options={} ) {
  return function wrapWithConnect( WrappedComponent ) { // WrappedComponent 需要包装的组件
    class Connect extends React.Component {
      constructor( props, context ) {
        super( props, context );
        this.store = context.store;
        this.state = {
          storeState: this.store.getState()
        }
      }

      componentDidMount() {
        let store = this.props.store;
        this.store.subcribe( ()=>{
          let newStoreState = store.getState();
          this.setState( function(){
            return {
              storeState: newStoreState
            }
          } )
        } )
      }

      render() {
        let storeState = this.state.storeState;
        let props = this.props;
        let stateProps = mapStateToProps( storeState, props );
        let dispatchProps = mapDispatchToProps( this.store.dispatch, props );
        let mergedProps = mergeProps( stateProps, dispatchProps, props );
        return <WrappedComponent {...mergedProps}/>
      }
      
    }
    return Connect;
  }
}

如何避免不不必要的更新

上面的代码会导致一个问题,就是每次只要 store 保存的 state 更新,那么所有订阅的组件都要去更新,无论组件关系的状态是否有变化,那么我们就需要在触发组件更新前做下比较

function connect( mapStateToProps, mapDispatchToProps, mergeProps, options={} ) {
  return function wrapWithConnect( WrappedComponent ) { // WrappedComponent 需要包装的组件
    class Connect extends React.Component {
      constructor( props, context ) {
        super( props, context );
        this.store = context.store;
        this.state = {
          storeState: this.store.getState()
        }
      }

      componentDidMount() {
        let store = this.props.store;
        this.store.subcribe( ()=>{
          let newStoreState = store.getState();
          // 1.
          // 比较 mapStateToProps 接收一个参数时候 返回的 props 有没有变化
          // 如果 mapStateToProps 接收的两个参数,那么还要看 props 有没有变化
          let newStateProps = mapStateToProps( newStoreState );
          if ( this.stateProps && shallowEqual(this.stateProps, newStateProps ) ) {
            return
          }
          this.stateProps = newStateProps;
          this.hasStoreStateChanged = true
          this.setState( function(){
            return {
              storeState: newStoreState
            }
          } )
        } )
      }

      componentWillReceiveProps(nextProps) {
        // 2.
        // 比较下 props 有没有变化
        if (!shallowEqual(nextProps, this.props)) {
          this.haveOwnPropsChanged = true
        }
      }

      shouldComponentUpdate() {
        // 3.
        // 如果 1 和 2 中任何有变化,都需要更新组件
        return this.haveOwnPropsChanged || this.hasStoreStateChanged
      }

      render() {
        let storeState = this.state.storeState;
        let props = this.props;
        let stateProps = mapStateToProps( storeState, props );
        let dispatchProps = mapDispatchToProps( this.store.dispatch, props );
        let mergedProps = mergeProps( stateProps, dispatchProps, props );
        return <WrappedComponent {...mergedProps}/>
      }
      
    }
    return Connect;
  }
}

最后即使 stateProps 有变化, props 有变化,如果最终 mergedProps 没有变化,那么 render 最后 return 出去的 组件也可以做缓存。所以源码里面在 render 里面还对最终 mergedProps 做了比较。这里就不详述了,因为思路已经带到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值