美文网首页
[源码] Redux React-Redux01

[源码] Redux React-Redux01

作者: woow_wu7 | 来源:发表于2021-09-23 08:39 被阅读0次
    image
    • redux中间件洋葱模型


      image
      image
    • redux中间件注意点


      image

    导航

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

    [react] Hooks

    [部署01] Nginx
    [部署02] Docker 部署vue项目
    [部署03] gitlab-CI

    [源码-webpack01-前置知识] AST抽象语法树
    [源码-webpack02-前置知识] Tapable
    [源码-webpack03] 手写webpack - compiler简单编译流程
    [源码] Redux React-Redux01
    [源码] axios
    [源码] vuex
    [源码-vue01] data响应式 和 初始化渲染
    [源码-vue02] computed 响应式 - 初始化,访问,更新过程
    [源码-vue03] watch 侦听属性 - 初始化和更新
    [源码-vue04] Vue.set 和 vm.$set
    [源码-vue05] Vue.extend

    [源码-vue06] Vue.nextTick 和 vm.$nextTick

    前置知识

    (1) 一些单词

    several 几个
    enhancer 增强器
    third-party 第三方
    potentially 潜在的
    

    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的值
    
    

    一些单词

    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复习

    image

    按中间件的使用流程来梳理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,
        [?observable]: observable
      }
    }
    
    

    (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
        }
      }
    }
    
    
    image
    image

    (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)
    • 函数较多,慢慢读吧

    项目源码 - 源码分析的地址

    资料

    redux源码 https://juejin.im/post/6844903600456466445
    图解洋葱模型(中间件的原理,重要)(这个老哥是真的强啊) https://juejin.im/post/6844903597776306190
    逐行阅读redux源码(一) createStore https://juejin.im/post/6844903710158487565#heading-0
    reacr-redux => Provider https://juejin.im/post/6844903735446110215
    react-redux 庖丁解牛 https://juejin.im/post/6844903488699236359
    reacr-redux => connect https://github.com/dwqs/blog/issues/38

    相关文章

      网友评论

          本文标题:[源码] Redux React-Redux01

          本文链接:https://www.haomeiwen.com/subject/igpngltx.html