coderliush / Blog

博客
0 stars 0 forks source link

react 系列之 react-redux 源码学习 #5

Open coderliush opened 4 years ago

coderliush commented 4 years ago

先复习一下 react-redux 的基本用法 Provider 包裹根组件,并传入 store

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './store'
import App from './App'

const rootElement = document.getElementById('root')
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
)

子组件通过 connect 关联 store, 第一个参数 mapStateToProps 将 store 中的 state 映射到 props 上。第二个参数 mapDispatchToProps 将 dispatch 映射到 props 上。所以子组件有了获取 state 和 修改 state 的能力。

import { connect } from 'react-redux'
import { increment, decrement, reset } from './actionCreators'

const mapStateToProps = (state /*, ownProps*/) => {
  return {
    counter: state.counter
  }
}

const mapDispatchToProps = { increment, decrement, reset }

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

接下来我们看一下 react-redux 源码 react-redux 导出这几个我们常用的对象

export {
  Provider,
  connectAdvanced,
  ReactReduxContext,
  connect,
  batch,
  useDispatch,
  createDispatchHook,
  useSelector,
  createSelectorHook,
  useStore,
  createStoreHook,
  shallowEqual
}

Provider

import React, { useMemo, useEffect } from 'react'
import { ReactReduxContext } from './Context'
import Subscription from '../utils/Subscription'

function Provider({ store, context, children }) {
  const contextValue = useMemo(() => {
    const subscription = new Subscription(store)
    subscription.onStateChange = subscription.notifyNestedSubs
    return {
      store,
      subscription
    }
  }, [store])

  const previousState = useMemo(() => store.getState(), [store])

  useEffect(() => {
    const { subscription } = contextValue
    subscription.trySubscribe()

    if (previousState !== store.getState()) {
      subscription.notifyNestedSubs()
    }
    return () => {
      subscription.tryUnsubscribe()
      subscription.onStateChange = null
    }
  }, [contextValue, previousState])

  const Context = context || ReactReduxContext

  return <Context.Provider value={contextValue}>{children}</Context.Provider>
}

React.createContext 创建 Context,共享全局的 state。value 传入 store 和 监听函数。

connect

connect 传入 mapStateToProps, mapDispatchToProps 返回的函数接收 component 做为参数。

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

connect.js 导出一个 warp 函数。createConnect 函数的作用是设置一些 connect 需要的默认值。 connect 前两个参数是我们传入的 mapStateToProps, mapDispatchToProps ,此外还传入了其它需要的默认参数。

export function createConnect({
  connectHOC = connectAdvanced,
  mapStateToPropsFactories = defaultMapStateToPropsFactories,
  mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
  mergePropsFactories = defaultMergePropsFactories,
  selectorFactory = defaultSelectorFactory
} = {}) (
  // 
  return function connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    {
      pure = true,
      areStatesEqual = strictEqual,
      areOwnPropsEqual = shallowEqual,
      areStatePropsEqual = shallowEqual,
      areMergedPropsEqual = shallowEqual,
      ...extraOptions
    } = {}
  )
  ... 
)

export default /*#__PURE__*/ createConnect()