redux-react 驱动视图源码分析

174 阅读1分钟
  • 首先react-redux在使用connect的时候,会将整个store挂在当前这个HOC的实例上,然后取出state,并将state挂在当前这个HOC的state上,代码如下:
class Connect extends Component {
     ......

      constructor(props, context) {
        super(props, context)
        this.version = version
        this.store = props.store || context.store

        invariant(this.store,
          `Could not find "store" in either the context or ` +
          `props of "${this.constructor.displayName}". ` +
          `Either wrap the root component in a <Provider>, ` +
          `or explicitly pass "store" as a prop to "${this.constructor.displayName}".`
        )

        const storeState = this.store.getState()
        this.state = { storeState }
        this.clearCache()
      }
      .......
 }
  • 之后会在componentDidMount 中做 Subscribe 代码如下
 componentDidMount() {
        this.trySubscribe()
      }
 trySubscribe() {
       if (shouldSubscribe && !this.unsubscribe) {
         this.unsubscribe = this.store.subscribe(::this.handleChange)
         this.handleChange()
       }
     }
  • Subscribe 方法,会将所有的回调注册到一个队列里面,代码如下
  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
  • 发起dispatch后,redux会同步调用所有注册的回调函数,代码如下
 function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }
  • 回调函数则触发setState,并更新HOC中的store的值副本,并比较两次的store的值,来确定store是否更改
 handleChange() {
        if (!this.unsubscribe) {
          return
        }

        const prevStoreState = this.state.storeState
        const storeState = this.store.getState()

        if (!pure || prevStoreState !== storeState) {
          this.hasStoreStateChanged = true
          this.setState({ storeState })
        }
      }
  • 从代码上来看,redux 依靠 shouldComponentUpdate 来判断是否需要执行render
 shouldComponentUpdate() {
        return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged
      }
  • 通过 componentWillReceiveProps 中对Props进行浅比较,来判断props是否更改
componentWillReceiveProps(nextProps) {
       if (!pure || !shallowEqual(nextProps, this.props)) {
         this.haveOwnPropsChanged = true
       }
     }
  • 那么从代码来看的话,只要发起了dispatch 就会产生新的sotre,会引发rerender