乐趣区

关于javascript:源码-Redux-ReactRedux01

  • 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 获取 state
ReactDOM.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.js
import 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.js
import actionType from './constant'
export const getUerName = (name)  => {
  return {
    type: actionType.GET_USERNAME,
    payload: name
  }
}





(6) home/constant.js
const 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 = 7


console.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 创立函数,调用返回一个 action
    
    
    if (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/…

退出移动版