react-redux源码研读

react-redux源码研读(版本:4.x)

最原始的使用redux数据流的方式是怎样的?

我们需要创建多个reducers,并且用combineReducers去合并我们的reducer,利用创建好的reducers,在用createStrore创建state状态,用Provider去包裹我们所有的组件并传递store数据。在使用出用connect链接到store,通过dispatch传递action传递type进去更改state的值。这样的流程大致是redux的工作流程。

第一步我们需要用combineReducers去合并reducer,combineReducers是怎样工作的呢?

combineReducers

接受一个对象,合并能力是由redux这个包提供的。

import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'

const todoApp = combineReducers({
  todos,
  visibilityFilter
})

export default todoApp

使用时是这样使用的。看源码

export default function combineReducers(reducers: ReducersMapObject) {
  const reducerKeys = Object.keys(reducers)
  const finalReducers: ReducersMapObject = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }

    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }
    // 定义了变量去接受reducers
  const finalReducerKeys = Object.keys(finalReducers)

  // This is used to make sure we don't warn about the same
  // keys multiple times.
  let unexpectedKeyCache: { [key: string]: true }
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let shapeAssertionError: Error
  // 检测传入的各个reducer是否正确
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }
// combineReducers得到的就是combination函数。在createStore有用到。
    // combination函数执行得到的结果,是一个对象,键和值是reducer,其实是我们传入的那个样子
  return function combination(
    state: StateFromReducersMapObject<typeof reducers> = {},
    action: AnyAction
  ) {
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(
        state,
        finalReducers,
        action,
        unexpectedKeyCache
      )
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    const nextState: StateFromReducersMapObject<typeof reducers> = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    hasChanged =
      hasChanged || finalReducerKeys.length !== Object.keys(state).length
    return hasChanged ? nextState : state
  }
}

combineReducers做了什么?它对我们传入的reduce做检测,是否为合法的reducers。我认为这是核心。

createStrore

这个函数可以得到我们Provider所需要的store参数,它接收combineReducers返回的函数combination,第二个

参数是初始值。源码走起,只看最后返回的东西,同样这个函数是redux提供的能力之一

  const store = ({
    dispatch: dispatch as Dispatch<A>,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  } as unknown) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
  return store

很明显,返回的就是一个对象,里面包裹了dispatch,subscribe等函数。

Provider(react-redux)

服务消费者,运用的是react的context,传递了store下去。

export default class Provider extends Component {
  getChildContext() {
    return { store: this.store }
  }

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

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

是一个高阶函数,返回新的组件,添加我们定义的对象进props。消费provider提供的store,会将store的dispatch和mapStateToProps返回的对象添加进props供组件使用。用作触发更改store的值。

先看传递给provider的store是什么

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux/src'
import { createStore } from 'redux/src'
import todoApp from './models/reducers/todos'
import App from './App'
const initState=[{aaa:'aaaa'}];
let store = createStore(todoApp,initState)

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

初始化了一个值为数组。

在看connect,这里贴关键代码,在connect高阶函数里面返回的是Connect组件,render函数内。

    render() {
        const {
          haveOwnPropsChanged,
          hasStoreStateChanged,
          haveStatePropsBeenPrecalculated,
          statePropsPrecalculationError,
          renderedElement
        } = this

        this.haveOwnPropsChanged = false
        this.hasStoreStateChanged = false
        this.haveStatePropsBeenPrecalculated = false
        this.statePropsPrecalculationError = null

        if (statePropsPrecalculationError) {
          throw statePropsPrecalculationError
        }

        let shouldUpdateStateProps = true
        let shouldUpdateDispatchProps = true
        // 第一次进来 renderElement没有直接跳过这个判断
        if (pure && renderedElement) {
          shouldUpdateStateProps = hasStoreStateChanged || (
            haveOwnPropsChanged && this.doStatePropsDependOnOwnProps
          )
          shouldUpdateDispatchProps =
            haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps
        }

        let haveStatePropsChanged = false
        let haveDispatchPropsChanged = false
        // 这个判断在每次render的时候都为false 跳过。
        if (haveStatePropsBeenPrecalculated) {
          haveStatePropsChanged = true
            // 为true 进入
            // 这里会顺序去调用合并,state,dispatch,最后将state,dispatch,添加到mergeProps里面去/
        } else if (shouldUpdateStateProps) {
          haveStatePropsChanged = this.updateStatePropsIfNeeded()
        }
        if (shouldUpdateDispatchProps) {
          haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded()
        }

        let haveMergedPropsChanged = true
        if (
          haveStatePropsChanged ||
          haveDispatchPropsChanged ||
          haveOwnPropsChanged
        ) {
          haveMergedPropsChanged = this.updateMergedPropsIfNeeded()
        } else {
          haveMergedPropsChanged = false
        }

        if (!haveMergedPropsChanged && renderedElement) {
          return renderedElement
        }

        if (withRef) {
          this.renderedElement = createElement(WrappedComponent, {
            ...this.mergedProps,
            ref: 'wrappedInstance'
          })
        } else {
            // 这里可以看出我们合并的props是mergedProps
          this.renderedElement = createElement(WrappedComponent,
            this.mergedProps
          )
        }

        return this.renderedElement
      }

// 三个函数的调用方式和处理方式差不多,
updateStatePropsIfNeeded() {
        const nextStateProps = this.computeStateProps(this.store, this.props)
        if (this.stateProps && shallowEqual(nextStateProps, this.stateProps)) {
          return false
        }

        this.stateProps = nextStateProps
        return true
      }
 computeStateProps(store, props) {
        if (!this.finalMapStateToProps) {
          return this.configureFinalMapState(store, props)
        }

        const state = store.getState()
        const stateProps = this.doStatePropsDependOnOwnProps ?
          this.finalMapStateToProps(state, props) :
          this.finalMapStateToProps(state)

        if (process.env.NODE_ENV !== 'production') {
          checkStateShape(stateProps, 'mapStateToProps')
        }
        return stateProps
      }

      configureFinalMapState(store, props) {
          //   const mapState = mapStateToProps || defaultMapStateToProps
          // 前面有得到过这个。是由我们传入的参数
        const mappedState = mapState(store.getState(), props)
        const isFactory = typeof mappedState === 'function'

        this.finalMapStateToProps = isFactory ? mappedState : mapState
        this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1

        if (isFactory) {
          return this.computeStateProps(store, props)
        }

        if (process.env.NODE_ENV !== 'production') {
          checkStateShape(mappedState, 'mapStateToProps')
        }
        return mappedState
      }

总得来说connect就是把用户自定的state和dispatch映射到props上。这就是connect所具备的功能。

dispatch

我们调用props下的dispatch实际是触发的store中的dispatch,看代码

  function dispatch(action: A) {
    try {
      isDispatching = true
        // currentReducer 其实就是执行的combineReducers返回的combination
      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
  }

当前的state最后得到在通过Provider得到的新的值去更新,

数据格式是

{
reducer:state,
reducer:state
}

是以reducer函数命名的对象,整个state是以reducer为key,state为值的键值对。

总结

redux的数据中心其实只是一个变量,他可以为任何的数据类型,我们每次dispatch的时候,实际是会去遍历所有的reducer之后封装成一个新的state,而action只是一个简单的对象而已,并没有很神奇的东西、action肯定会有一个type键去确认你当前所想做的事的描述。

主要运用的技术点:

  1. 高阶组件
  2. react的context
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值