资讯专栏INFORMATION COLUMN

redux浅析

galois / 1879人阅读

摘要:概念是一个状态管理容器使用可以更好的管理和监测组件之间需要通信的数据。参考源码参考链接

redux概念

redux是一个状态管理容器,使用redux可以更好的管理和监测组件之间需要通信的数据。

redux基本原则 单一数据源

在redux中,整个应用保持一个数据源,数据源是一个树形的结构

状态只读

状态只读意思是不能直接修改,需要通过dispatch action方式才可以,返回的是一个新的状态对象

纯函数操作改变数据

改变数据的纯函数是指reducer,如下形式

reducer(state, action)

函数内部通常是switch case这些代码,函数的结果完全由两个参决定,同样的输入条件,会产生同样的输出结果

redux使用
//reducer.js
export default (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1
    case "DECREMENT":
      return state - 1
    default:
      return state
  }
}
//main.js
import { createStore } from "redux"
const store = createStore(counter)
store.getState()  //获取状态
store.dispatch({ type: "INCREMENT" })  //改变状态

说明 上面是纯redux的一个简单示例, 目的是改变store内部计数器的状态
结合react使用例子,可以参考我之前的分析

redux分析

redux的核心非常简洁, 提供了中间件机制可以拓展功能。核心模块主要有以下几部分

  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
下面依次来分析,首先是createStore模块,主要实现逻辑如下
export default function (reducer, preloadedState) {
    let currentState = preloadedState;
    let listeners = [];
    function getState() {
        return currentState
    }
    //派发action
    function dispatch(action) {
        //通过旧状态和新action计算出新状态
        currentState = reducer(currentState, action);
        //执行监听函数
        listeners.forEach(listener => listener());
    }
    //派发了一个动作进行初始化
    dispatch({ type: "@@redux/INIT" });
    //供外界订阅本仓库中状态的变化 
    function subscribe(listener) {
        listeners.push(listener);
        //返回一个取消订阅函数
        return function () {
            listeners = listeners.filter(item => item != listener)
        }
    }
    return {
        getState, dispatch, subscribe
    }
}

说明 这个模块主要通过闭包的方式创建一个store,封装了处理逻辑,对外只提供getState(获取状态),dispatch(派发action),subscribe(订阅改变)三个接口。

combineReducers主要实现逻辑如下
export default function combineReducers(reducers) {
    const finalReducerKeys = Object.keys(reducers)
    //返回的是合并后的reducer
    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]
          //计算子store中,state的值
          const nextStateForKey = reducer(previousStateForKey, action)
        
          nextState[key] = nextStateForKey
          //如果没改变的话,还是用之前的state
          hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        }
        return hasChanged ? nextState : state
      }
    }
    

说明 源码有快200行了,考虑了各种边界情况,核心逻辑就上面一点, 和并多个reducer成一个对象

bindActionCreators主要实现逻辑如下
export default function bindActionCreators(actionCreators, dispatch) {
  const keys = Object.keys(actionCreators)
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    //把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象
    if (typeof actionCreator === "function") {
    //使用 dispatch 包装 action creator 以便子组件可以直接调用。
      boundActionCreators[key] = function() { return dispatch(actionCreator.apply(this, arguments)) }
    }
  }
  return boundActionCreators
}

说明 惟一会使用到 bindActionCreators 的场景是把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 dispatch 或 Redux store 传给它。

applyMiddleware
export default function applyMiddleware(...middlewares) {
    //下面这句话在create.js中 enhancer(createStore)(reducer, preloadedState)时会执行,目的是创建一个增强版的store
  return (createStore) => (...args) => {
    //还是调用原生createStore逻辑进行初始化创建store
    const store = createStore(...args)
    let dispatch = store.dispatch
    let chain = []
    // 传递给中间件使用
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    //加工中间件,注入middlewareAPI
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    //形成洋葱中间件形式包裹dispatch结构的形式
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

说明 applyMiddleware中间件机制,可以在处理store前后加一些通用处理,实现这个机制功能最重要,也是最难理解的一步操作就是compose,见下面分析。

compose
export default function compose(...funcs) {
  
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

说明 将多个函数合并成一个函数,嵌套执行,举个例子,例如compose(f, g, h)后就变成f(g(h())),而 函数的执行顺序从右到左,h() g() f()

总结

为了方便理解,我主要将源码中关键主流程逻辑做了摘要简化输出,加以注释说明,额外想说的一点感想就是,在redux生态体系中用到了大量函数式编程中的一些东西,例如高阶函数,以及随时间不断增长的action动作列表(可以等价思考认为redux对这个列表进行reduce操作),而处理action的就是纯函数理念的reducer,还有处理异步的中间件thunk函数等等。

参考源码
"redux": "3.7.2",
参考链接
https://redux.js.org/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94556.html

相关文章

  • 浅析Redux数据流

    摘要:原文地址数据流通过这张流程图,我们可以更好的理解和直接数据如何流通,关系如何映射。函数只是一个纯函数,它接收应用程序的当前状态以及发生的,然后返回修改后的新状态或者有人称之为归并后的状态。的更新意味着更新。 原文地址:https://github.com/YutHelloWo... showImg(https://segmentfault.com/img/bVRQRK?w=1205&h...

    chaosx110 评论0 收藏0
  • 浅析`redux-thunk`中间件源码

    摘要:大多的初学者都会使用中间件来处理异步请求,其理解简单使用方便具体使用可参考官方文档。源码的源码非常简洁,出去空格一共只有行,这行中如果不算上则只有行。官方文档中的一节讲解的非常好,也确实帮我理解了中间件的工作原理,非常推荐阅读。 总觉得文章也应该是有生命力的,欢迎关注我的Github上的博客,这里的文章会依据我本人的见识,逐步更新。 大多redux的初学者都会使用redux-thunk...

    wing324 评论0 收藏0
  • 浅析Redux源码

    摘要:用法源码由在年创建的科技术语。我们除去源码校验函数部分,从最终返回的大的来看。这个返回值无法被识别。洋葱模型我们来看源码源码每个都以作为参数进行注入,返回一个新的链。改变原始组数,是一种副作用。 @(Redux)[|用法|源码] Redux 由Dan Abramov在2015年创建的科技术语。是受2014年Facebook的Flux架构以及函数式编程语言Elm启发。很快,Redux因其...

    lifesimple 评论0 收藏0
  • 前端进阶资源整理

    摘要:前端进阶进阶构建项目一配置最佳实践状态管理之痛点分析与改良开发中所谓状态浅析从时间旅行的乌托邦,看状态管理的设计误区使用更好地处理数据爱彼迎房源详情页中的性能优化从零开始,在中构建时间旅行式调试用轻松管理复杂状态如何把业务逻辑这个故事讲好和 前端进阶 webpack webpack进阶构建项目(一) Webpack 4 配置最佳实践 react Redux状态管理之痛点、分析与...

    BlackMass 评论0 收藏0
  • react路由浅析

    摘要:浏览器端使用的和集成使用时会用到中路由分类基于提供的和事件来保持和的同步。路由剖析在上面的示例中是转发的枢纽在这个中转站有很多线路通过开关可以启动列车的运行乘坐列车就可以发现新大陆。 引言 在使用react做复杂的spa开发中,开发中必不可少的就是react-router,它使用Lerna管理多个仓库, 在browser端常使用的几个如下所示 react-router 提供了路由的...

    jackzou 评论0 收藏0

发表评论

0条评论

galois

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<