Vuex与Redux对比

*仅从设计理念、使用角度进行对比,不涉及实现原理。*

尤大也说过VUEX是吸收了Redux的经验,放弃了一些特性并做了一些优化,代价就是VUEX只能和VUE配合。

而Redux则是一个纯粹的状态管理系统,React利用React-Redux将它与React框架结合起来。

VUEX与React-Redux:一个是针对VUE优化的状态管理系统,一个仅是常规的状态管理系统(Redux)与React框架的结合版本。它们必然在都具备常规的状态管理的功能之外,针对性地对各自所对应的框架还会有一些更优的特性,并且React-Redux还有一些衍生项目。DVA就是一个基于对React-Redux进行封装并提供了一些优化特性的框架,所以下文也会结合DVA进行对比。

#### 设计理念:
虽然很多文章都提到说不要为了用状态管理而用状态管理,但是状态管理对于前端单页应用的管理思想还是很精髓的:
- Web应用是一个状态机,视图与状态是一一对应的。

![image](https://vuex.vuejs.org/flow.png)

我认为,一旦认同这种模式并在项目组使用了状态管理,就要严格的在整个应用中都采用这种模式。因此,基于这种特性,我们需要一种机制或者框架:使得我们能够管理状态,感知变化,并将状态映射为页面表现。

**Redux**,本身就是一个单纯的状态管理者,我们不追溯它的历史,从使用角度来说:它提供一个全局的对象store,store中包含state对象用以包含所有应用数据,并且store提供了一些reducer方法。这些方法可以自定义,使用调用者得以改变state的值。state的值仅为只读,如果需要更改则必须只能通过reducer。

有了状态保存,有了读写机制,Redux这一套状态管理的框架对于web应用的状态机管理的思想就是可用的。

**React-Redux**,简单来说,它提供了一些接口,用于Redux的状态和React的组件展示结合起来,以用于实现状态与视图的一一对应。

**VUEX**,吸收了Redux的思想,并且针对web应用的开发模式和VUE框架做了优化。所以它在实现了全量Redux的思想以外,为了与VUE框架结合,它也具备了类似React-Redux中的与框架结合的功能(尽管具体使用方式可能有差异),此外还一些更好用的特性,下文会说到。

**DVA**,则是对React-Redux进行了封装,并结合了Redux-Saga等中间件,而且使用了model概念,也相当于在React-Redux的基础上针对web应用开发做了优化。(个人认为DVA框架的开发者可能是对VUEX有所借鉴的)

所以说,看起来VUE家族的一个VUEX,就可以匹敌React家族的这些封装封装再封装……

###### VUEX数据流向图

![image](https://vuex.vuejs.org/vuex.png)


###### DVA数据流向图

![image](https://zos.alipayobjects.com/rmsportal/PPrerEAKbIoDZYr.png)


#### 对比:
因为VUEX可以以一敌多,接下来将对以下三方面进行分析
- Redux vs VUEX
- React-Redux vs VUEX
- DVA vs VUEX

#### I

###### Redux
- 核心对象:store
- 数据存储:state
- 状态更新提交接口:==dispatch==
- 状态更新提交参数:带type和payload的==Action==
- 状态更新计算:==reducer==
- 限制:reducer必须是纯函数,不支持异步
- 特性:支持中间件

###### VUEX
- 核心对象:store
- 数据存储:state
- 状态更新提交接口:==commit==
- 状态更新提交参数:带type和payload的mutation==提交对象/参数==
- 状态更新计算:==mutation handler==
- 限制:mutation handler必须是非异步方法
- 特性:支持带缓存的getter,用于获取state经过某些计算后的值

###### Redux vs VUEX 对比分析
store和state是最基本的概念,VUEX没有做出改变。其实VUEX对整个框架思想并没有任何改变,只是某些内容变化了名称或者叫法,通过改名,以图在一些细节概念上有所区分。
- **VUEX弱化了dispatch的存在感**。VUEX认为状态变更的触发是一次“提交”而已,而调用方式则是框架提供一个提交的commit API接口。
- **VUEX取消了Redux中Action的概念**。不同于Redux认为状态变更必须是由一次"行为"触发,VUEX仅仅认为在任何时候触发状态变化只需要进行mutation即可。Redux的Action必须是一个对象,而VUEX认为只要传递必要的参数即可,形式不做要求。
- **VUEX也弱化了Redux中的reducer的概念**。reducer在计算机领域语义应该是"规约",在这里意思应该是根据旧的state和Action的传入参数,"规约"出新的state。在VUEX中,对应的是mutation,即"转变",只是根据入参对旧state进行"转变"而已。

总的来说,VUEX通过弱化概念,在任何东西都没做实质性削减的基础上,使得整套框架更易于理解了。

另外VUEX支持getter,运行中是带缓存的,算是对提升性能方面做了些优化工作,言外之意也是鼓励大家多使用getter。

#### II

###### React-Redux
- 状态注入组件:==<Provider/>组件结合connect方法==
- ==容器组件:通过connect关联了state的组件,并被传入dispatch接口==
- 展示组件:不与state或dispatch直接产生关系
- 特性:connect支持mapStatesToProps方法,用于自定义映射

###### VUEX
- 状态注入组件:==Vue.use(Vuex)将Vuex应用为全局的plugin,再将store对象传入根VUE实例==
- ==容器组件:没有这个概念==
- 展示组件:在组件中可以获取this.$store.state.*,也进行this.$store.commit()等等
- 特性:VUEX提供mapState,mapGetter,mapMutation等方法,用于生成store内部属性对组件内部属性的映射

###### React-Redux vs VUEX 对比分析
通过使用方式上的较大差异,也可以看出理念上的不同。
- **和组件结合方式的差异**。VUE通过VUEX全局插件的使用,结合将store传入根实例的过程,就可以使得store对象在运行时存在于任何vue组件中。而React-Redux则除了需要在较外层组件结构中使用<Provider/>以拿到store之外,还需要显式指定容器组件,即用connect包装一下该组件。这样看来我认为VUE是更推荐在使用了VUEX的框架中的每个组件内部都使用store,而React-Redux则提供了自由选择性。而VUEX即不需要使用外层组件,也不需要类似connect方式将组件做一次包装,我认为出发点应该是可能是为了避免啰嗦。
- **容器组件的差异**。React-Redux提倡容器组件和表现组件分离的最佳实践,而VUEX框架下不做区分,全都是表现(展示)组件。我觉得不分优劣,React-Redux的做法更清晰、更具有强制性和规范性,而VUEX的方式更加简化和易于理解。

总的来说,就是谁包谁,谁插谁的问题。Redux毕竟是独立于React的状态管理,它与React的结合则需要对React组件进行一下外包装。而VUEX就是为VUE定制,作为插件、以及使用插入的方式就可以生效,而且提供了很大的灵活性。

#### III

###### DVA
- 划分模块:提供了model的概念,一个model相当于是store的一个小块,DVA负责将这些小块整合成全局store而不需开发者关心。每个model提供配置namespace便于使用。
- 异步方法调用:==effect==。由于包装了Redux-Saga,DVA支持将配置的effect方法做为model的一部分。每个effect方法是一个Generator函数,将异步方法(Promise)调用同步化,框架提供迭代器,执行时串行执行。通过包装,开发者可以通过dispatch调用Action,以和调用reducer一样的方式调用effect方法。而effect内部提供API,用户获取参数、获取state、调用其他reducer等等。

###### VUEX
- 划分模块:允许将store分割成module,概念与DVA中的类似。与DVA一样,它也提供访问自身state和全局state的方法,也提供通过namespace/module名的方式供组件使用的办法,也提供动态注册、模块重用等。
- 异步方法调用:==Action==。Action类似于mutation,但是它内部支持异步调用。它无法直接更改state,但是可以使用context.commit()方式调用mutation。而对于开发者来说,不像DVA将effects和reducers的调用方式搞的相同,VUEX中的Action需要使用另一个API--dispatch接口来调用。它可以返回Promise对象,供调用者进行后续处理。
- 特性:支持双向绑定

###### DVA vs VUEX 对比分析
它们将store拆分成模块的出发点是相同的,这也是大型应用开发所必备的。并且模块化的思路都是一样的。但是异步方法调用方面有所不同:
- **DVA更倾向于支持同步化的代码写法与执行方式**。这样的好处是开发者使用effects和reducers时感觉是一样的。开发者可以适当规避使用Promise从而几乎不用接触异步概念,但是却需要接受Generator方法这种新事物。我认为学习成本并没有降低,可能好处就是最终代码比较简化,出错率较低吧。当然这对于框架本身来说会带来一定的复杂性。
- **VUEX倾向于将异步方法区分开**。Action就是异步方法,而mutation就是非异步方法。声明方式、调用方式、入参等等,都是有明显区别的。这样的好处是时刻在提醒开发者需要将异步方法加以区分注意,并且可以很常规地使用Promise,使用异步特性。

*VUEX还有个特性就是它的表单类组件的双向绑定。和VUEX结合之后,也是支持绑定到VUEX中的state上的。*

VUEX的异步方法的提交方式,注意是“dispatch一个Action”。这在概念上是和Redux中的状态更新提交是一致的。从VUEX数据流向图也能看出,VUEX也是建议只向外部暴露Action供调用。这样一来,VUEX在使用上更加接近Redux了。

总的来说,DVA和VUEX我认为肯定是有借鉴学习的成分在里面的,对异步的使用方面也没有孰优孰劣。我们也完全可以找到或者封装一个React-Redux中间件,以在React中使用类似的纯异步方法;也可以基于VUE与VUEX做开发,使得它可以支持Generator甚至async函数方式将异步代码写法同步化。


猜你喜欢

转载自blog.csdn.net/hyupeng1006/article/details/80755667