• redux中间件洋葱模型

  • redux中间件留神点

导航

[[深刻01] 执行上下文](https://juejin.im/post/684490...
[[深刻02] 原型链](https://juejin.im/post/684490...
[[深刻03] 继承](https://juejin.im/post/684490...
[[深刻04] 事件循环](https://juejin.im/post/684490...
[[深刻05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490...
[[深刻06] 隐式转换 和 运算符](https://juejin.im/post/684490...
[[深刻07] 浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...
[[深刻08] 前端平安](https://juejin.im/post/684490...
[[深刻09] 深浅拷贝](https://juejin.im/post/684490...
[[深刻10] Debounce Throttle](https://juejin.im/post/684490...
[[深刻11] 前端路由](https://juejin.im/post/684490...
[[深刻12] 前端模块化](https://juejin.im/post/684490...
[[深刻13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490...
[[深刻14] canvas](https://juejin.im/post/684490...
[[深刻15] webSocket](https://juejin.im/post/684490...
[[深刻16] webpack](https://juejin.im/post/684490...
[[深刻17] http 和 https](https://juejin.im/post/684490...
[[深刻18] CSS-interview](https://juejin.im/post/684490...
[[深刻19] 手写Promise](https://juejin.im/post/684490...
[[深刻20] 手写函数](https://juejin.im/post/684490...

[[react] Hooks](https://juejin.im/post/684490...

[[部署01] Nginx](https://juejin.im/post/684490...
[[部署02] Docker 部署vue我的项目](https://juejin.im/post/684490...
[[部署03] gitlab-CI](https://juejin.im/post/684490...

[[源码-webpack01-前置常识] AST形象语法树](https://juejin.im/post/684490...
[[源码-webpack02-前置常识] Tapable](https://juejin.im/post/684490...
[[源码-webpack03] 手写webpack - compiler简略编译流程](https://juejin.im/post/684490...
[[源码] Redux React-Redux01](https://juejin.im/post/684490...
[[源码] axios ](https://juejin.im/post/684490...
[[源码] vuex ](https://juejin.im/post/684490...
[[源码-vue01] data响应式 和 初始化渲染 ](https://juejin.im/post/684490...
[[源码-vue02] computed 响应式 - 初始化,拜访,更新过程 ](https://juejin.im/post/684490...
[[源码-vue03] watch 侦听属性 - 初始化和更新 ](https://juejin.im/post/684490...
[[源码-vue04] Vue.set 和 vm.$set ](https://juejin.im/post/684490...
[[源码-vue05] Vue.extend ](https://juejin.im/post/684490...

[[源码-vue06] Vue.nextTick 和 vm.$nextTick ](https://juejin.im/post/684790...

前置常识

plainObject

  • 纯对象
  • plainObject 是指通过对象字面量形式创立或者通过构造函数创立的对象,即 ( <font color=red>{}</font> ) 或者 ( <font color=red>new Object()</font> ) 形式创立的对象
  • 纯对象如何了解:

    • 比方 Date,Regexp,Function,Array等就不属于纯对象,然而用 typeof 判断他们都会返回 'object'
    • 比方 const a = { name: 'woow_wu7'} 这样申明的对象就是一个纯对象,因为是通过对象字面量申明的对象

context

  • React.createContext(defaultValue)

    • 创立 context 对象

      • context对象上蕴含

        • Provider 组件
    • const MyContext = React.createContext(defaultValue)

      • 如果React渲染一个 ( 订阅 ) 了 ( MyContext ) 对象的组件时,这个组件会从组件树中离 (<font color=red> 本身最近</font> ) 的那个匹配的 ( <font color=red>Provider</font> ) 中读取到以后的 ( <font color=red>context</font> ) 值
      • 参数

        • defaultValue:<font color=red>只有在所处的组件树中没有 Provider 时,defaultValue 才会失效</font>
        • 留神:

          • <MyContext.Provider value={/* 某个值 */}>中的value是undefined时,defaultValue不失效
  • Context.Provider

    • <MyContext.Provider value={/* 某个值 */}>
    • 参数

      • value
    • 作用

      • 容许生产组件订阅 context 的变动
      • 当 Provider 的 value 值发生变化时,它外部的所有生产组件都会从新渲染
      • Provider 及其外部 consumer 组件都不受制于 shouldComponentUpdate 函数,因而当 consumer 组件在其先人组件退出更新的状况下也能更新
  • Class.contextType

    • MyClass.contextType = MyContext

      • 将 MyContext 即一个context对象,赋值给一个组件的 <font color=red>contextType</font> 属性
      • 那么就能够通过在组件外部通过 <font color=red>this.context</font> 获取到 context 的值

        • 能够在组件的任何生命周期中通过 this.context 拜访到context的值
  • Context.Consumer

    • 在函数式组件中实现订阅 context
  • 实例

    import React from 'react'import { connect } from 'react-redux'import { bindActionCreators } from 'redux'import * as actions from './action'import MyContext from '../../context'import './index.less'class ContextTest extends React.Component {  render() {      return (          <div>              <div>context-test</div>              <ContextTypeText />              <MyContext.Provider value={{ author: 'woow_wu7', date: '2020-04-25' }}>                  <MyContext.Consumer>                      {                          ({ author, date }) => {                              console.log('函数组件通过MyContext.Consumer组件包裹函数组件,函数组件的参数就是context的值')                              return (                                  <div>                                      {                                          author                                      }                                  </div>                              )                          }                      }                  </MyContext.Consumer>              </MyContext.Provider>          </div>      )  }}// MyContext.Provider// MyContext.Consumer// Consumer组件用于函数式组件,用Consumer包裹函数组件后,函数组件的参数就是最近的Provider的提供的context的值const mapStateToProps = (state) => {  return {      ...state  }}const mapDispatchToProps = (dispatch) => {  return bindActionCreators(actions, dispatch)}export default connect(mapStateToProps, mapDispatchToProps)(ContextTest)class ContextTypeText extends React.Component {  // class式组件  render() {      const { appName } = this.context      console.log(this.context, 'class组件通过class.contextType = MyContext来获取context')      return (          <>              {appName}          </>      )  }}ContextTypeText.contextType = MyContext// Class.contextType = MyContext// 把MyContext赋值组件的contextType后,就能够在组件内通过 this.context 获取context的值
  • 官网 context api解说

    一些单词

    preload:预载,预装enhancer:增强器,放大器 bound:肯定会,跳跃 nest:巢,嵌套plain:纯的plainObject:纯对象invoked: 调用assert:断言

Redux

  • createStore
  • combineReducers
  • applyMiddleware
  • bindActionCreators
  • compose

    React-Reux

  • Provider
  • connect
  • useSelector
  • useDispatch
  • useStore
  • createSelectorHook
  • createDispatchHook
  • createStoreHook
  • shallowEqual shallow是浅的意思
  • batch
  • connectAdvanced
  • ReactReduxContext

2021/01/02温习

  • [[redux和react-redux]源码剖析仓库](https://github.com/woow-wu7/7...

按中间件的应用流程来梳理redux源码

(1) index.js- 入口文件- 应用 react-redux 的 Provider 包裹根组件    - Provider的作用是通过context将store传入子组件,子组件通过 connect 获取 stateReactDOM.render(  <Provider store={store}> // --------------------- Provider    <BrowserRouter>      <Layout />    </BrowserRouter>  </Provider>  , document.getElementById('root'));  (2) store.js- 创立store实例const allReducer = {  home: HomeReducer,  banner: BannerReducer,  recommend: RecomendReducer, // ----------------- 用到了redux-thunk}const store = createStore(  combineReducers({ // --------------------------- combineReducer 将所有的reducer合成一个总的reducer    ...allReducer  }),  composeWithDevTools( // ------------------------ enhancer增强器    applyMiddleware(thunkMiddleware, loggerMiddleware) // ---------- applyMiddleware 将多个中间件通过洋葱模型执行副作用,并dispatch(action)  ))(3) 在组件模块中- 通过 connect 连贯 store- 将 store state 和 改装过后的 action creators 注入到 props 中传给各组件const mapStateToProps = (state) => { // ---------------------------------------------- mapStateToProps  return {    ...state  }}const mapDispatchToProps = (dispatch) => { // --------------------------------------- mapDisPatchToProps  return bindActionCreators(actions, dispatch) // ----------------------------------- bindActionCreators}export default connect(mapStateToProps, mapDispatchToProps)(Home) // ---------------- connect(4) home/reducer.jsimport actionType from './constant.js'const initialState = {  name: 'wang'}const reducer = function(state=initialState, action) {  switch (action.type) {    case actionType.GET_USERNAME:      return {        ...state,        name: action.payload      }    default:      return {        ...state      }  }}export default reducer(5) home/action.jsimport actionType from './constant'export const getUerName = (name)  => {  return {    type: actionType.GET_USERNAME,    payload: name  }}(6) home/constant.jsconst actonType = {  GET_USERNAME: 'GET_USERNAME'}export default actonType

redux-thunk中间件源码剖析

// redux-thunk 源码// 1// createThunkMiddleware函数签名如下// (extraArgument) => ({dispatch, getState}) => next => action => { ...具体依据action的类型来判断 }// 2// 真正导出的是:// (1) action是一个对象: ({dispatch, getState}) => next => action => next(acion) // (2) action是一个函数: ({dispatch, getState}) => next => action => action(dispath, getState, extraArgument)// 3 // 具体案例在 在 admin-system/interview-react/Knowledge/reduxSourceCode组件中function createThunkMiddleware(extraArgument) {  return ({ dispatch, getState }) => next => action => {    // 如果 action 是一个函数    if (typeof action === 'function') {      return action(dispatch, getState, extraArgument);      // 比方dispatch这样一个函数      // 1. <button onClick={add}>间接dispatch一个函数</button>      // 2. const add = () => { dispatch(handleThunk) }      // 3. 如下      // const handleThunk = (dispatch: any, getState: any) => {      //   setTimeout(() => {      //     dispatch({      //       type: actionType.ADD_INTERVIEW,      //       payload: 1      //     })      //   }, 2000)      // }    }    // 如果 action 不是函数,就调用 next(action) 将 action对象 传递到下一个中间件    return next(action);  };}const thunk = createThunkMiddleware();thunk.withExtraArgument = createThunkMiddleware;export default thunk;

(1) createStore()

createStore(reducer, preloadedState, enhancer)

  • 参数:

    • <font color=red>reducer</font>

      • 根 reducer,能够应用 ( combineReducers ) 将多个reducer组合成一颗总树
      • 纯函数,承受 ( prevState ) 和 ( action ),返回 ( 新的state )
    • <font color=red>preloadedState</font>

      • 初始化state,初始化整个store
      • preload: 预载,预装的意思
    • <font color=red>enhancer</font>

      • enhancer是一个函数,叫做增强器,能够在dispatch一个action达到reducer之前做一些加强解决,如:打印日志,dispatch一个函数等
      • applyMiddleware(中间件1,中间件2...) 就是一个加强函数
  • 返回值:

    • enhancer不存在

      • <font color=red>返回 store 对象</font>

        • dispatch
        • subscribe
        • getState
        • replaceReducer
        • observable
        • 先走流程,这几个函数前面剖析
    • enhancer存在,并且是函数

      • <font color=red>返回 enhancer(createStore)(reducer, preloadedState)</font>

        • enhancer如果是applyMiddleware()的话,返回值也是一个对象
        • enhancer返回值:

          • 像这样的对象{..store, dispatch}
          • 前面dispatch会笼罩掉store中的dispatch函数,对象中前面的属性会笼罩后面的属性
    createStore.js先剖析次要的流程
  • 如果enhancer是函数就返回一个

    • enhancer(createStore)(reducer, preloadedState)
      // 在实在的开发过程中个别都会应用 enhancer 增强器
      // 个别是调用 applyMiddleware(thunkMiddleware)
  • 如果enhancer不存在就返回一个

    • { dispatch,subscribe,getState,replaceReducer,[?observable]: observable } 对象

    createStore.js

    export default function createStore(reducer, preloadedState, enhancer) {
    if (
    (typeof preloadedState === 'function' && typeof enhancer === 'function') ||
    (typeof enhancer === 'function' && typeof arguments[3] === 'function')
    ) {
    throw new Error(

    'It looks like you are passing several store enhancers to ' +  'createStore(). This is not supported. Instead, compose them ' +  'together to a single function.'

    )
    }

    if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
    }

    if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {

    throw new Error('Expected the enhancer to be a function.')

    }

    return enhancer(createStore)(reducer, preloadedState)
    }

    if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
    }

    return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,

    }
    }

(2) applyMiddleware()

applyMiddleware(middleware1, middleware2, ...) 就是 createStore() 的参数中的 enhancer()

  • <font color=red>applyMiddleware() 函数签名</font>

    • (...middlewares) => createStore => (...args) => ({...store, dispatch})
  • <font color=red>applyMiddleware() 返回值</font>

    • 一个对象
    • {...store, dispatch}
  • 在实在的我的项目中,个别这样应用 createStore 和 applyMiddleware

    • createStore(combineReducers({...rootReducer}), applyMiddleware(thunkMiddleware, loggerMiddleware))

      • 这里曾经是调用了applyMiddleware()的第一层,返回的是一个函数

        • 返回的函数签名:createStore => (...args) => ({...store, dispatch})
        • middlewares曾经在内存中,造成闭包
  • 实际上第一步是这样的: createStore(rootReducer, (createStore) => (...args) => ({...store, dispatch}))
  • <font color=red>redux中间件</font>

    • redux的中间件是一个高阶函数
    • 函数签名:({dispatch, getState}) => (next) => (action) => next(action)
  • <font color=red>compose()</font>

    • 函数签名:(...funcs) => funcs.reduce((a, b) => (...args) => a(b(...args)))
    • 返回值:一个函数
    • 作用:

      • 从右至左,将左边函数的返回值作为右边函数的参数传入
      • compose函数就是洋葱模型
      • compose(A, B, C)(arg) === A(B(C(arg)))
    • 调用时:dispatch = compose(...chain)(store.dispatch)
    • chain相似:chain = [(next) => (action) => next(action), (next) => (action) => next(action)]
import compose from './compose'export default function applyMiddleware(...middlewares) {  // 在createStore()中调用enhancer时,传入的参数是    // enhancer(createStore)(reducer, preloadedState)    // 这是一个高阶函数,柯里化函数    // 1) 执行 const resFn = enhancer(createStore),返回值也是一个函数    // 2) 执行 consr res = resFn(reducer, preloadedState)  // 最终 applyMiddleware 返回的是 ({...store, dispatch}) 对象  return createStore => (...args) => {    // 这里的args是一个数组    // 具体的值就是:[reducer,preloadedState]    const store = createStore(...args)    let dispatch = () => {      // 申明dispatch办法      throw new Error(        'Dispatching while constructing your middleware is not allowed. ' +          'Other middleware would not be applied to this dispatch.'      )    }    const middlewareAPI = {      getState: store.getState,      dispatch: (...args) => dispatch(...args)    }    const chain = middlewares.map(middleware => middleware(middlewareAPI))    // 这里middleware数组中有两个中间件:thunkMiddleware,loggerMiddleware    // middleware的函数签名如下:      // ({dispatch, getState}) => (next) => (action) => next(action)        // chain = [(next) => (action) => next(action), (next) => (action) => next(action)]         dispatch = compose(...chain)(store.dispatch)    // compose      // 函数签名:(...funcs) => funcs.reduce((a, b) => (...args) => a(b(...args)))       // compose()的作用是:从右至左,将左边函数的返回值作为右边函数的参数传入      // compose(A, B, C)(arg) === A(B(C(arg)))      // compose(A, B, C)(arg) === A(B(C(arg))) 这个临时能够作为论断记住,上面会按步骤拆解        // 当初假如有三个中间件      // const M1 = (store) => (next) => (action) => { console.log('A开始');  next(action); console.log('A完结')}      // const M2 = (store) => (next) => (action) => { console.log('B开始');  next(action); console.log('B完结')}      // const M3 = (store) => (next) => (action) => { console.log('C开始');  next(action); console.log('C完结')}      // 留神下面三个中间件的第一个参数 store 中只有getState, dispacth两个函数            // chain = [(next)=>(action)=>{M1...}, (next)=>(action)=>{M2...}, (next)=>(action)=>{M3...}]      // 当初 dispatch = chain.reduce((a, b) => (...args) => a(b(...args)))(store.dispatch)       // dispatch的最终状态      // dispatch = M1(M2(M3(store.dispatchj)))       // 留神这里的M1M2M3是去除了(store)参数的这一层的返回的函数 (next)=>(action)=>{M1...}      // 以下是具体步骤            // 第一步:dispatch = funcs.reduce((a, b) => (...args) => a(b(...args)))(store.dispatch)              // 第一次reduce            // a是:            (next) => (action) => { console.log('A开始');  next(action); console.log('A完结')}            // b是:            (next) => (action) => { console.log('B开始');  next(action); console.log('B完结')}            // b(...args)是:   (action) => { console.log('B开始');  (...args)(action); console.log('B完结')}            // a(b(...args)) 就是调用a中的 next(actions) 换成next就是 (action) => { console.log('B开始');  (...args)(action); console.log('B完结')}函数,参数是action            // a(b(...args))是:(action) => { console.log('A开始');  console.log('B开始');  (...args)(action); console.log('B完结') console.log('A完结')}            // 总返回值:(...args) => (action) => { console.log('A开始');  console.log('B开始');  (...args)(action); console.log('B完结') console.log('A完结')}                    // 第二次reduce            // a是:(...args) => (action) => { console.log('A开始');  console.log('B开始');  (...args)(action); console.log('B完结') console.log('A完结')}            // b是:(next) => (action) => { console.log('C开始');  next(action); console.log('C完结')}            // b(...args)是:(action) => { console.log('C开始');  (...args)(action); console.log('C完结')}            // a(b(...args))是:(action) => { console.log('A开始');  console.log('B开始');  console.log('C开始');  (...args)(action); console.log('C完结') console.log('B完结') console.log('A完结')}            // 总返回值:(...args) => (action) => { console.log('A开始');  console.log('B开始');  console.log('C开始');  (...args)(action); console.log('C完结') console.log('B完结') console.log('A完结')}        // 第二步:将第一步返回的函数 (...args) => (action) => {...(...args)(action);...} 传入参数 (store.dispatch) 并执行                dispatch = (action) => { console.log('A开始');  console.log('B开始');  console.log('C开始');  store.dispatch(action); console.log('C完结') console.log('B完结') console.log('A完结')}                // 第二步格式化一下:          // dispatch = (action) => {          //   console.log('A开始')          //   console.log('B开始')          //   console.log('C开始')          //   store.dispatch(action)          //   console.log('C完结')          //   console.log('B完结')          //   console.log('A完结')          // }    return {      ...store,      dispatch,       // dispatch就是一个函数,通过redux中间件执行各种副作用后,调用store对象上的 dispatch()办法      // 而store对象又是通过 createStore()办法生成的,外面有dispatch()办法的实现            // store上的dispatch办法,次要干了两件事件      // 1. 传递action给reducer,更新state      // 2. state更新后,执行监听数组中的所有监听函数listener    }  }}


(3) compose()

  • <font color=red>比方:compose(a, b, c)(1)</font>
  • 函数签名:(...funcs) => funcs.reduce((a, b) => (...args) => a(b(...args)))
  • 返回值:一个函数,因为能够通过compose()()这样的形式调用,就阐明compose()返回了一个函数
  • 作用:

    • 从右至左,将左边函数的返回值作为右边函数的参数传入
    • compose函数就是洋葱模型
    • compose(A, B, C)(arg) === A(B(C(arg)))
// redux4.0.5// compose源码export default function compose(...funcs) {  if (funcs.length === 0) {    return arg => arg  }  if (funcs.length === 1) {    return funcs[0]  }  return funcs.reduce((a, b) => (...args) => a(b(...args)))}// 当compose的参数// 长度为0时,即没有参数时,返回一个函数,该函数间接将传入的参数返回// 长度为1时,返回这个参数函数// 长度大于1时,返回参数数组执行reduce迭代的后果,reduce返回在这里返回的是一个函数// 留神:// compose()的返回值是一个函数,所以相当于高阶函数,能够通过compose(a,b,c)(d)这样的形式调用--当初假如有这样一段代码const a = (number) => number + 1;const b = (number) => number + 2;const c = (number) => number + 3;const res = compose(a, b, c)(1) // compose的参数有三个,所以执行 return funcs.reduce((a, b) => (...args) => a(b(...args)))// 所以 res = [a, b,  c].reduce((a, b) => (...args) => a(b(...args)))返回了一个函数, 传入的参数是 1, 并调用执行// 先看 compose(a, b, c) 返回了什么//  [a, b,  c].reduce((a, b) => (...args) => a(b(...args)))// 第一步:    // 累积变量: a    // 以后变量: b    // b(...args)返回值:(...args) + 2    // a(b(...args))返回值:(...args) + 2 + 1    // 第一步总返回值:  (...args) => (...args) + 2 + 1 留神返回值是一个函数,这个函数并未被调用// 第二步:    // 累积变量:  (...args) => (...args) + 2 + 1,上一步的返回值作为新的累积变量    // 以后变量: c    // c(...args)返回值:(...args) + 3    // ab(c(...args)):即调用ab(),参数是 c(...args)返回值(...args) + 3        // ab函数 (...args) => (...args) + 2 + 1        // ab函数参数 (...args) + 3        //  ab函数最终的返回值:(...args) + 3 + 2 + 1    //第二步总返回值:(...args) => (...args) + 3 + 2 + 1// 第三步const res = compose(a, b, c)(1)// 1. compose(a, b, c)返回了一个函数:(...args) => (...args) + 3 + 2 + 1// 2. const res = composeRes(1)// 3. const res = 1 + 3 + 2 + 1 // 4. const res = 7console.log(res, 'res') // 7// 4 + 2 + 1总结:1. 从以上过程能够看出,只有最左边的中间件能够接管多个参数,右边函数的参数都是左边函数的返回值
  • compose 2020/12/9温习

    redux中的compose函数源码function compose(...funcs) {if (funcs.length === 0) { // ------------- (1) 如果compose函数没有传入参数,就返回一个函数,该函数间接将参数值返回  return arg => arg}if (funcs.length === 1) { // ------------- (2) 如果compose函数传入了一个参数,那么间接返回该函数  return funcs[0]}// ---------------------------------------- (3) 当compose的参数大于1个参数时,返回迭代器reduce,而reduce返回的是一个函数return funcs.reduce((a, b) => (...args) => a(b(...args)))}const a = (num) => num + 1;const b = (num) => num + 2;const c = (num) => num + 3;const resFn = compose(a, b, c)(1)console.log(resFn, 'resFn')compose剖析:(1) 如果compose函数没有传入参数,就返回一个函数,该函数间接将参数值返回(2) 如果compose函数传入了一个参数,那么间接返回该函数(3) 当compose的参数大于1个参数时,返回迭代器reduce,而reduce返回的是一个函数
  • compose(a, c, c)
  • 本例中compose函数一共传入了两层参数

    • 第一层:一共传入了三个函数作为参数,别离是 a b c
    • 第二层:传入了参数 1

    第一步:第一层函数被调用 compose(a, b, c)
    [a, b, c].reduce((a, b) => (...args) => a(b(...args)))
    第二步:

    • reduce第一次迭代
    • (...args) => a(b(...args))

      • b(...args)执行的后果作为a的参数 => a((...args) + 2)
      • a((...args) + 2)执行的后果 => (...args) + 2 + 1
    • reduce的总的返回值 => (...args) => (...args) + 2 + 1
      第三步:
    • reduce的第二次迭代
    • (...args) => ab迭代后果(c(...args))
    • c(...args)执行的后果作为 ab迭代后果的参数 => ((...args) + 3) => (...args) + 2 + 1
    • ab((...args) + 3)执行的后果 => (...args) + 3 + 2 + 1
    • reduce的总的返回值 => (...args) => (...args) + 3 + 2 + 1
      第四步:
    • compose的最终状态
    • const composex = (...args) => (...args) + 3 + 2 + 1
      第五步:第二层函数被调用compose(a,b,c)返回的函数在调用(1)
    • composex(1)
    • 返回值 1+3+2+1
    • 7

(4) bindActionCreators()

  • bindActionCreators(actionCreators, dispatch)
  • 参数

    • ( <font color=red>actionCreators</font> ) 是一个 ( <font color=red>函数</font> ) 或者一个 ( <font color=red>对象</font> )
    • dispatch
  • 返回值

    • 如果参数actionCreators是一个<font color=red>函数</font>

      • 间接返回 bindActionCreator() 函数的执行后果,即一个<font color=red>函数</font>
      • 返回值是:() => dispatch(actionsCreator.apply(this, arguments)) => () => dispatch(action)
    • 如果参数actionCreators是一个<font color=red>对象</font>

      • 返回一个 boundActionCreators 对象,即一个<font color=red>对象</font>
      • 返回值是:{actionCreator的函数名: () => dispatch(actionCreator.apply(this, arguments)), ...}
    • 返回值总结

      • 如果参数actionCreators是一个函数,返回一个函数
      • 如果参数actionCreators是一个对象,返回对象
  • bindActionCreator()

    • 函数签名:(actionCreator, dispatch) => () => dispatch(actionCreator.apply(this, arguments))
    • 简化函数签名:(actionCreator, dispatch) => () => dispatch(action)
    function bindActionCreator(actionCreator, dispatch) {return function() {  return dispatch(actionCreator.apply(this, arguments))}}export default function bindActionCreators(actionCreators, dispatch) {if (typeof actionCreators === 'function') {  return bindActionCreator(actionCreators, dispatch)}// 如果 actionCreators 是一个函数,就间接返回 bindActionCreator(actionCreators, dispatch) 执行的后果// bindActionCreator(actionCreators, dispatch)  // 返回的是一个函数:() => dispatch(actionCreator.apply(this, arguments))// 即:如果参数actionCreators是一个函数,返回上面这样一个函数// () => dispatch(actionCreator.apply(this, arguments))// () => dispatch(action)// 因为actionCreator是action创立函数,调用返回一个actionif (typeof actionCreators !== 'object' || actionCreators === null) {  throw new Error(    `bindActionCreators expected an object or a function, instead received ${      actionCreators === null ? 'null' : typeof actionCreators    }. ` +      `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`  )}// 如果参数actionCreators不是对象或者为null,则报错// 上面是参数actionCreators是一个对象的状况const boundActionCreators = {}for (const key in actionCreators) {  const actionCreator = actionCreators[key]  if (typeof actionCreator === 'function') {    boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)    // boundActionCreators    // key是:函数名    // value是: () => dispatch(actionCreator.apply(this, arguments)) 这样一个函数    // value简化:() => dispatch(action)  }}return boundActionCreators}

(5) combineReducers()

  • combineReducers(reducers)
  • 参数

    • reducers 是一个<font color=red>对象</font>

      • key:reducer函数的 函数名
      • value:reducer函数
  • 返回值

    • 返回 combination() 函数
  • <font color=red>combination(state, action)</font>

    • 返回值:

      • 返回一个对象
      • <font color=red>每个reducer()执行返回的新的state组成的对象</font>

        • key:传入combineReducers(reducers)的reducers对象中的key
        • value: 是state
      • {key1: state1, key2: state2} 这样的对象
    combineReducers() 外围代码export default function combineReducers(reducers) {const reducerKeys = Object.keys(reducers)const finalReducers = {}for (let i = 0; i < reducerKeys.length; i++) {  const key = reducerKeys[i]  if (process.env.NODE_ENV !== 'production') {    if (typeof reducers[key] === 'undefined') {      // 如果以后环境不是生成环境并且reducers的某个key对应的值是undefined,抛错      warning(`No reducer provided for key "${key}"`)    }  }  if (typeof reducers[key] === 'function') {    // reducer是函数,就收集到finalReducers对象中    // 等于过滤出reducers中是函数的reducer    finalReducers[key] = reducers[key]  }}const finalReducerKeys = Object.keys(finalReducers)return function combination(state = {}, action) {  let hasChanged = false  const nextState = {}  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    // 1. hasChanged = true 则 hasChanged为true    // 2. 只有有一次nextStateForKey 和 previousStateForKey不同,就阐明整个state不同,hasChanged就为true  }  hasChanged =    hasChanged || finalReducerKeys.length !== Object.keys(state).length  return hasChanged ? nextState : state  // 如果state变动了,返回新的state (nextState)  // 如果state没有变动,返回就的state (state)}}

(6) createStore 中具体的办法

  • 先温习下第一步中的createStore()办法

    • createStore(reducer, preloadedState, enhancer)
      1. 如果enhancer不存在,就返回本人外部定义的几个办法组成的对象:getState, dispatch, subscribe, replaceReducer,observable等
      1. 如果enhancer存在,并且是函数的话,返回返回 enchancer(createStore)(reducer, perloadedState)

        • enhancer()函数申明:以applyMiddleware为例
        • applyMiddleware()的函数申明:(middlewares) => createStore => (...args) => ({...store, dispatch})
        • 在 applyMiddleware()外部也会调用传入的 createStore(reducer, preloadedState) 生成 store

(6-1) createStore - dispatch()

  • dispatch(action)
  • 参数:

    • action对象,必须要有type字段
  • 返回值

    • action
  • <font color=red>次要作用</font>:

    • <font color=red> 1. 将action传递给reducer纯函数,更新state</font>
    • <font color=red> 2. 更新state后,执行监听数组中所有的订阅了该state的监听函数</font>
    dispatch()export default function createStore(reducer, preloadedState, enhancer) {let currentReducer = reducer // 缓存reducer,reducer是传入的参数let currentState = preloadedState // 缓存preloadedState,preloadedState是传入的参数let currentListeners = [] // 新建监听者数组let nextListeners = currentListeners // 赋值,即两个变量指向同一个堆地址,批改相互影响,留神辨别赋值,浅拷贝,深拷贝let isDispatching = false // 标记位,用来标记 dispatch 执行过程function dispatch(action) { // 接管action对象作为参数  if (!isPlainObject(action)) {     // 如果不是纯对象抛错    // 纯对象是必须通过对象字面量申明的对象 或者 通过构造函数申明的对象      // 即 {} 或者 new Object() 生成的对象      // 数组,Date对象,Regexp对象,Error对象,Function对象等都不是纯对象    // 这里action不是对象就抛错,如果不是对象,可能是个函数,比方异步提交的函数,就须要通过redux中间件解决      throw new Error(      'Actions must be plain objects. ' +        'Use custom middleware for async actions.'    )  }  if (typeof action.type === 'undefined') {    // action对象中必须要有type字段    throw new Error(      'Actions may not have an undefined "type" property. ' +        'Have you misspelled a constant?'    )  }  if (isDispatching) {    // 如果正在dispatching,抛错    throw new Error('Reducers may not dispatch actions.')  }  try {    isDispatching = true    currentState = currentReducer(currentState, action)    // reducer函数的作用就是:接管prevState和action,返回一个新的state    // 这里将新的state赋值给变量  } finally {    isDispatching = false  }  const listeners = (currentListeners = nextListeners)  for (let i = 0; i < listeners.length; i++) {    const listener = listeners[i]    listener()    // 当reducer纯函数更新了最新的state后,会执行监听数组中的所有监听函数  }  return action}return {  dispatch,}}

(6-2) createStore - subscribe()

  • 参数

    • listener 监听函数
  • 返回值

    • 返回 unSubscribe() 函数
    • unSubscribe()负责勾销订阅监听事件
  • 次要作用

    • 增加监听函数 listener
    • 返回勾销监听的函数 unSubscribe
    subscribe()export default function createStore(reducer, preloadedState, enhancer) {let currentListeners = []let nextListeners = currentListeners // 赋值,批改相互影响,两个变量指针指向同一个堆地址let isDispatching = false// isDispatching 初始值为false// isDispatching  // true:在dispatch()中调用reducer()前isDispatching会被批改为true  // false:更新完state后isDispatching会被批改为false function ensureCanMutateNextListeners() {  if (nextListeners === currentListeners) {    nextListeners = currentListeners.slice()    // 做一层浅拷贝    // 当两个对象的属性值是根本类型的数据时,批改互不影响    // 留神辨别赋值,浅拷贝,深拷贝的区别  }}function subscribe(listener) {  if (typeof listener !== 'function') {    // listener必须是个函数    throw new Error('Expected the listener to be a function.')  }  if (isDispatching) {    // 只执行dispatch过程中,不容许subscribbr    throw new Error(      'You may not call store.subscribe() while the reducer is executing. ' +        'If you would like to be notified after the store has been updated, subscribe from a ' +        'component and invoke store.getState() in the callback to access the latest state. ' +        'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'    )  }  let isSubscribed = true  ensureCanMutateNextListeners()  nextListeners.push(listener)   // 增加监听函数到nextListeners  // 保障 nextListeners 和 currentListeners 两个数组中是不同的listener  return function unsubscribe() {    if (!isSubscribed) {      // 没有监听函数间接返回      return    }    if (isDispatching) {      // 在dispatch()执行时,不能取消订阅      // 因为idispatch(action)次要做两件事件        // 1. 将action传递给reducer纯函数,去更新state        // 2. state更新之后,去执行监听数组中的所有监听函数      throw new Error(        'You may not unsubscribe from a store listener while the reducer is executing. ' +          'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'      )    }    isSubscribed = false    ensureCanMutateNextListeners()    const index = nextListeners.indexOf(listener)    nextListeners.splice(index, 1)    // 从nextListeners中删除该 listener  }}return {  subscribe,}}

(6-3) createStore - getState()

getState()function getState() {    if (isDispatching) {      throw new Error(        'You may not call store.getState() while the reducer is executing. ' +          'The reducer has already received the state as an argument. ' +          'Pass it down from the top reducer instead of reading it from the store.'      )    }    return currentState  }

(6-4) createStore - replaceReducer()

replaceReducer()  function replaceReducer(nextReducer) {    if (typeof nextReducer !== 'function') {      throw new Error('Expected the nextReducer to be a function.')    }    currentReducer = nextReducer // 间接赋值传入的新的nextReducer    dispatch({ type: ActionTypes.REPLACE })     // 触发内置的replace事件    // 即执行dispatch()办法,action是 { type: ActionTypes.REPLACE }  }
















React-Redux

Provider

  • <Provider store={store}>
  • 次要的作用:

    • <font color=red>把 store 通过context的办法传递给Context.Provider组件包裹的子组件</font>
    • <font color=red>在 Provider 组件外部,判断 store.getState() 获取的 state 是否变动,变动了通过setState()更新storeState</font>
    • setState更新最新的store中的state后,Provider组件包裹的所有 ( 子组件 ) 就会 ( 从新渲染 )
    import React, { Component } from 'react'import PropTypes from 'prop-types'import { ReactReduxContext } from './Context'class Provider extends Component {constructor(props) {  super(props)  const { store } = props  // 从 props中获取 store  // Provider组件中是具备 store属性的  // <Provider store={store}>  this.state = {    storeState: store.getState(),    store  }}componentDidMount() {  this._isMounted = true  // _isMounted 示意是否挂载  // _isMounted 在 componentDidMount 中为 true  // _isMounted 在 componentWillUnmount 中为 false,卸载了  this.subscribe()  // 调用该组件中自定义的办法subscribe   // 该办法的次要作用:   // 比对是不是最新的storeState,如果storeState变动了,就用setState()更新state   // state更新后,<Provider />所有子组件就都会从新渲染}componentWillUnmount() {  if (this.unsubscribe) this.unsubscribe()  // 卸载时,勾销订阅  this._isMounted = false}componentDidUpdate(prevProps) {  // componentDidUpdate(prevProps, prevState)   if (this.props.store !== prevProps.store) {    // 更新后,store变动,勾销订阅    if (this.unsubscribe) this.unsubscribe()    this.subscribe()    // 调用该组件中自定义的办法subscribe    // 该办法的次要作用:      // 比对是不是最新的storeState,如果storeState变动了,就用setState()更新state      // state更新后,<Provider />所有子组件就都会从新渲染  }}subscribe() {  const { store } = this.props  this.unsubscribe = store.subscribe(() => { // 定义unsubscribe勾销订阅的办法    // store.subscribe(listener)    // 参数      // 参数是一个监听函数    // 返回值      // 返回 unsubscribe    const newStoreState = store.getState()    if (!this._isMounted) {      return    }    this.setState(providerState => {      // If the value is the same, skip the unnecessary state update.      if (providerState.storeState === newStoreState) {        // storeState 没有变动,就间接return,应用以前的 storeState        return null      }      return { storeState: newStoreState }      // storeState变动了,应用最新的newStoreState,更新storeState    })  })  // Actions might have been dispatched between render and mount - handle those  const postMountStoreState = store.getState()  if (postMountStoreState !== this.state.storeState) {    this.setState({ storeState: postMountStoreState })    // storeState变动就更新为最新的tore.getState()的值  }}render() {  const Context = this.props.context || ReactReduxContext  // ReactReduxContext 是通过 React.createContext(null)生成的 Context 对象  //  <Context.Provider value={this.state}> 提供 context 给 Context.Provider 包裹的所有子组件  // calss类型的组件,在 class.contextType = Context 后,通过  this.context获取 context的值  // function类型的组件,能够通过 Context.Provider 和 Context.Consumer 这样的形式,包裹function组件后,在参数中获取 context  return (    <Context.Provider value={this.state}>      {this.props.children}    </Context.Provider>  )}}Provider.propTypes = {store: PropTypes.shape({  subscribe: PropTypes.func.isRequired,  dispatch: PropTypes.func.isRequired,  getState: PropTypes.func.isRequired}),context: PropTypes.object,children: PropTypes.any}export default Provider

connect

  • connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])(component)
  • 函数较多,缓缓读吧

我的项目源码 - 源码剖析的地址

  • 7-react-admin-ts源码剖析redux react-redux
  • 具体文件夹:src => SOURCE-CODE-ANALYSIS => REDUX文件夹中

材料

redux源码 https://juejin.im/post/684490...
图解洋葱模型(中间件的原理,重要)(这个老哥是真的强啊) https://juejin.im/post/684490...
逐行浏览redux源码(一) createStore https://juejin.im/post/684490...
reacr-redux => Provider https://juejin.im/post/684490...
react-redux 庖丁解牛 https://juejin.im/post/684490...
reacr-redux => connect https://github.com/dwqs/blog/...