• Redux与mobx对比我们应该如何选择?


    Redux 和 Mobx 都是当下比较火热的数据流模型,一个背靠函数式,似乎成为了开源界标配,一个基于面向对象,低调的前行。


    以下内容会严格遵循下面三个观点:

    目的一致

    都是状态管理库,用来管理应用的内部状态

    受众大体一致

    一般都会被用到react中,虽然说这并不是必须的,你当然也可以用到vue或者angular里,但是,大多数情况下,都不会这么做

    可相互替代

    在项目之初,你可以选择二者之一来满足你的项目需求,但是到某一天你突然觉得另一个更和你气味相投,你完全可以花点时间迁移过去,你会发现,它似乎也能满足你的那些需求

    学习难度对比:

    mobX的学习中,你可以听信关于30分钟快速入门的神话,因为它真的很简单,并且在这三十分钟过去之后,你唯一需要花的时间就是偶尔翻翻文档就可以自如的使用它了。

    redux的入门学习也没那么难,即使有些概念显得比较抽象,你最多需要多花上半个小时就可以掌握它们了,但是当你真的去使用的时候,你会发现这一切原来并非想象的那么简单,你不得不花更多的时间来学习更多:

    当你需要异步的时候,你不得不考虑redux-thunk,你怎么可能不需要异步想用Promise,没问题,先看看redux-promise-middleware怎么样想搞个日志之类的东西,redux-logger已经准备好了。

    工作量对比(以下代码直接在nodejs环境下测试):

    一般来讲,这里应该用一个couter之类的示例来做
     
     const { createStore } = require('redux')
      const ADD = 'ADD'
      const initState = {count: 0}
      // reducer
      function counter(state = initState, action) {
        switch(action.type) {
          case ADD:
            return {...state, count: state.count + action.payload.count}
          default:
            return state
        }
      }
      // actions
      const AddOne = () => ({type: ADD, payload: {count:1}})
      // store
      const store = createStore(counter)
      store.subscribe(() => console.log(store.getState()))
      setInterval(() => store.dispatch(AddOne()), 1000)
    不算注释,大约15行左右,那么,mobx想要具备压倒性的优势,应该极力控制自己的大小才对

    一个mobx的counter大概得长成这样吧
      
    const { observable, autorun } = require('mobx')
      const appState = observable({
        counter: 0,
        add(value){this.counter += value}
      })
      autorun(() => console.log(appState.counter))
      setInterval(() => appState.add(1), 1000)
    好像只用了7行,约莫是redux实现的一半大

    我的天哪,多出了那么多行代码,我还要不要下班了

    内存开销对比:

    大小只是浮于表面的东西,对于应用更友好的东西,才是核心的要点

    在写redux的action的时候,总是需要用到扩展语句或者Object.assign()的方式来得到一个新的state,这一点对于JavaScript而言是对象的浅拷贝,它对内存的开销肯定是大于mobX中那样直接操作对象属性的方式大得多。

    这一点比较6,算是一个可被重视的问题

    以上内容黑得主角很明显是属于redux的,那,万一我们换个视角看看呢

    状态管理的集中性:

    mobX中竟然有这样的写法:

      const {observable} = require('mobx')
      const appState = observable({ counter: 0 })
      appState.counter += 1

    直接修改状态?这和react的理论完全相悖啊,还怎么和react搭配使用啊,我的状态万一被同事给悄悄改了可是会引发一场战争的啊,还是开启严格模式吧。
    你说redux做的怎么样?试试不通过action更新一下state,当然不能成功啊。

    样板代码的必要性:

    关于样板代码,就要追溯到redux的基本设计选择了,redux三大原则:

    单一数据源
    State 是只读的
    使用纯函数来执行修改

    所以可以说是这些样本代码保证了state的状态的可管理性,毕竟所有的东西都是泾渭分明的,让出错的可能性和找问题的成本降到了最低。

    以上,使用mobX入门简单,构建应用迅速,但是当项目足够大的时候,还是使用redux,如果的确对mobX爱不释手,那还是开启严格模式,再加上一套状态管理的规范吧。

    函数式 vs 面向对象

    首先任何避开业务场景的技术选型都是耍流氓,我先耍一下流氓,首先函数式的优势,比如:

    无副作用,可时间回溯,适合并发。
    数据流变换处理很拿手,比如 rxjs。
    对于复杂数据逻辑、科学计算维的开发和维护效率更高。
    当然,连原子都是由带正电的原子核,与带负电的电子组成的,几乎任何事务都没有绝对的好坏,面向对象也存在很多优势,比如:

    javascript 的鸭子类型,表明它基于对象,不适合完全函数式表达。
    数学思维和数据处理适合用函数式,技术是为业务服务的,而业务模型适合用面向对象。
    业务开发和做研究不同,逻辑严谨的函数式相当完美,但别指望每个程序员都愿意消耗大量脑细胞解决日常业务问题。

    Redux vs Mobx

    那么具体到这两种模型,又有一些特定的优缺点呈现出来。

    Redux:

    数据流流动很自然,因为任何 dispatch 都会导致广播,需要依据对象引用是否变化来控制更新粒度。
    如果充分利用时间回溯的特征,可以增强业务的可预测性与错误定位能力。
    时间回溯代价很高,因为每次都要更新引用,除非增加代码复杂度,或使用 immutable。
    时间回溯的另一个代价是 action 与 reducer 完全脱节,数据流过程需要自行脑补。原因是可回溯必然不能保证引用关系。
    引入中间件,其实主要为了解决异步带来的副作用,业务逻辑或多或少参杂着 magic。
    但是灵活利用中间件,可以通过约定完成许多复杂的工作。
    对 typescript 支持困难。

    Mobx:

    数据流流动不自然,只有用到的数据才会引发绑定,局部精确更新,但免去了粒度控制烦恼。
    没有时间回溯能力,因为数据只有一份引用。
    自始至终一份引用,不需要 immutable,也没有复制对象的额外开销。
    没有这样的烦恼,数据流动由函数调用一气呵成,便于调试。
    业务开发不是脑力活,而是体力活,少一些 magic,多一些效率。
    由于没有 magic,所以没有中间件机制,没法通过 magic 加快工作效率(这里 magic 是指 action 分发到 reducer 的过程)。
    完美支持 typescript。

    到底如何选择

    一般前端数据流不太复杂的情况,使用 Mobx,因为更加清晰,也便于维护;如果大型项目建议使用redux
  • 相关阅读:
    Dijkstra单源最短路模板
    Naming Company CodeForces
    Naming Company CodeForces
    CF
    CF
    Present CodeForces
    9绑定方法与非绑定方法
    pycharm设置连接
    8封装的意义和拓展性
    property特性
  • 原文地址:https://www.cnblogs.com/it-Ren/p/13424321.html
Copyright © 2020-2023  润新知