你可能不需要vuex

来源:互联网 发布:速卖通翻译软件 编辑:程序博客网 时间:2024/05/29 15:59
你可能不需要 Vuex
 

目录

  • 组件化
  • 组件通信
  • 状态管理
  • Vuex 是什么
  • Vuex 有什么特点
  • Vuex 解决了什么问题
  • 什么类型的数据适合放在 Vuex 管理
  • 工具
  • 总结
  • 参考
  • 扩展阅读

写这篇文章的主要目的是在现在的公司推荐使用 Vue,而在使用 Vue 的时候很多同事对为什么要使用 Vuex 不理解,我本身是没有使用过 Vue 或者 Vuex 写过实际项目;有过一年左右的 React 和 Redux 相关技术的项目实践,主要是根据对等的一点经验所写;不当之处,欢迎讨论。

 
Web Components
* shadow DOM
* Custom Element
* Template ElementHTML
* HTML imports
西西
* 
* 
* 
* 
-- xufei2015
 对组件的粒度进行细分,可以分为:

* UI component: 纯 UI 组件,可以维护本地的 UI State,接收 props 作为数据渲染,保持纯函数形式,具有可复用性。
* Logic component: 带有逻辑的 UI 组件,与数据打交道。

组件化这个词,在 UI 这一层通常指“标签化”,也就是把大块的业务界面,拆分成若干小块,然后进行组装。狭义的组件化一般是指标签化,也就是以自定义标签(自定义属性)为核心的机制。广义的组件化包括对数据逻辑层业务梳理,形成不同层级的能力封装。

 
 

组件通信

应用在组件化之后,组件之间必然存在某种联系;组件化意味着协同工作,通常存在着 父子组件兄弟组件跨级组件 等组件关系,那么组件之间如何进行协调工作,即组件通信;

在 Vue 中,父子组件的关系可以总结为 props downevents up

  • 父子组件通信1:父组件通过 props 向下传递数据给子组件
  • 子父组件通信3:子组件通过 events 给父组件发送消息
    • 使用 $on(eventName) 监听事件
    • 使用 $emit(eventName) 触发事件
  • 非父子组件通信1:使用一个空的 Vue 实例作为中央事件总线 
    可以想象到在简单的 父子子父组件之间的通信是很轻松的,通过propsevents即可实现;但是往往我们的应用可能不只有这么简单的层级关系,在多层跨级组件如果通过props去传递,那意味着一层一层的往子组件传递,最终你可能不知道当前组件的数据最终来自哪个父组件(当然你可以逆着方向一层一层往上找),通过events事件机制显然也存在着类似的问题。如果你觉得这样也可以接受,你可能不需要 Vuex;但如果你在想有没有什么好的模式优雅的去解决,你可以继续阅读下面的部分。

    状态管理
     

     
     JavaScript JavaScript  state  
     state  UI 
     state  model  model  view 
     model  model  view 
    state 
    -- Redux 
     

      

在应用中,组件之间的通信其实是归根于应用的状态管理;而应用的状态是来自多方面的,如何对状态进行管理,提高代码的可维护性,提升开发效率;大多数主流框架对数据状态管理也都有了对应的方案:

  • React 专注于 UI 层,社区为其提供了 Redux、Mbox 等状态管理库
  • Vue 的团也提供了 Vuex 状态管理库
  • 还有一些专门解决数据层的库,如 RxJS

回到本文的讨论点,这里我们暂且只讨论 Vue;Vue 的核心库只关注视图层,单文件组件,其模板、逻辑和样式是内部耦合的,侧重数据和视图的同步;Vue 本身并没有对数据状态的管理进行处理,但其提供了另外一个类似 Redux 的解决方案 Vuex,一个集中式状态管理的库;也就是说,你可能不需要 Vuex,它只是对你应用状态进行管理的一个库。

Vuex 是什么

 
Vuex  Vue.js ****
-- from vuex docs (updated in 2016-05-27)
Vuex  Vue.js ****
****
-- from vuex docs (updated in 207-05-20)
 上面的定义是摘自 Vuex1 在 GitHub 上的文档,分别于 2016/05/27 和 2017/05/20 的更新记录;从中我们可以梳理一下关键词:
  • 集中式状态管理模式(注意是强调管理应用的所有组件的状态)
  • 可预测(前提是以相应的规则作为保证)

先不着急看下面的内容,如果你看到以上两点特性,脑海已经有了答案,能很好的向你的同事解释清楚,前提是你的同事完全没有任何 Vuex 的经验,那下面的内容你可以直接忽略。你也应该知道你的应用**是否需要 Vuex 了**。

 Vuex 有什么特点

从上面的定义中可以知道 Vuex 的特点其实就是下面两点:

  • 集中式状态管理
  • 可预测

什么是集中式状态管理模式

在说集中式管理模式之前,我们可以先来想想常见的处理方式是怎样的,即每个组件维护自身的数据和状态,自给自足,分而治之;其思路大致如下:
* 定义组件自身的初始数据
* 在组件内获取异步数据
* 根据数据渲染更新视图

 
// 
<template>
  <h2>single file component</h2>
<template>
<script>
  export default {
    // 
    data() {
    
    },
    
    // 
    created() {
      this.fetchData()
    },
    
    methods {
      fetchData() {
        // do something
      }
    }
  }
</script>
 

 可简单对比 React 的思路:

 
// https://github.com/xufei/blog/issues/19#issuecomment-85989838
var render = function(Model) {
  return View;
}
event_loop(function(){
  var currentView = render(currentModel);
  map_view_into_user_interface(currentView);
})
 

 

 
西
西 Single File Component 
...
 


集中式状态管理模式则以一个全局单例模式管理应用的状态,类似于全局对象,但不完全一样。

  • Vuex 的状态管理存储是响应式的:就是当你的组件使用到了 Vuex 的某个状态,一旦它发生改变了,所有关联的组件都会自动更新相对应的数据。

     
  • 不能直接修改 Vuex 的状态:修改 Vuex 的状态唯一途径是**提交(commit) mutations 来实现修改**

     如上图,Vuex为Vue Components建立起了一个完整的生态圈,包括开发中的API调用一环。围绕这个生态圈,简要介绍一下各模块在核心流程中的主要功能:
    • Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
    • dispatch:操作行为触发方法,是唯一能执行action的方法。
    • actions:操作行为处理模块。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
    • commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
    • mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
    • state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
    • getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。 
     
    Vuedispatchaction
    commitmutationstate
    gettersstateVue Components

    集中式状态管理的好处

    相对于分治(碎片化)的状态管理,多个状态分散的跨越在不同组件交互在各个角落,每个 View 会有相对应的 Model 维护状态;而集中式管理模式则用于将分散于组件的状进行集中化管理,提供一个全局的 store 存储管理应用的状态。集中式的状态管理可以让整体的状态变化更加明晰,尤其是配合各自的 devtools。它具备以下特点:

    • components share state(组件之间共享状态)
    • state should be accessible from everywhere(所有状态可以方便获取)
    • components need to mutate the state(组件可以修改状态)
    • components need to mutate the state of another component(组件可以修改其他组件的状态)   集中式状态管理的弊端
    • 上面提到**集中式存储管理应用的所有组件的状态**,而应用的状态上文已经有提到,这里大致可以分为:
      * UI 状态:用户输入的状态
      * 数据状态:服务端传过来的数据状态
      * 客户端信息:设备信息的状态
      * 其他...

      这里是有歧义的,集中式存储管理应用的所有状态,按照字面意思是将所有的状态都集中式管理,也就是存到 Vuex 的全局单一 store 中,显然我们是不能这样去理解的,应该视应用场景而定的,大致也可以分为以下几种:

      • 对于用户输入的状态,比如控制模态框的显示隐藏,我们一般在组件内处理消化;对于需要需要跨组件通信的,则可以存储在全局的 store 中,我们可以将这一类状态称之为本地状态(local state)。

      • 对于服务端传过来的数据状态,按照大多数的实践是存储在全局的 store 中,这样可以在任意的组件中都可以使用;当然,也可以只将多组件的共享的数据存储在全局的 store 中,单个组件需要的数据内部处理消化,组件销毁时对应的数据状态也会销毁。

      对于客户端的信息或者一些其他的数据状态与上面两种方式在一定程度上也是相似的。这一切看起来并没什么问题,然而细细想想,当一个应用的足够复杂时,我们该如何去设计我们的数据模型,本地共享的状态是存在 store 还是通过事件机制去处理,服务端的数据是一股脑都塞给全局的 store 存在内存里还是视应用场景而定,在 Vuex 的文档或者是 Redux 文档这都没有唯一的答案。假设服务端传过来的数据都存在 store, 那最终的 store 会有多大,这是一个值得探索的问题。那究竟什么样的数据适合存储在全局的 store 中?

      另外,使用 Vuex 必须按照上述 Vuex 的工作流程去进行,定义对应的 actions, mutations等等,这显然是在强制约定你以相应的规则去编写你的应用,对大多数新人来说,这是繁琐的。就相当于你得到了一定的好处,那你也得相应的有所付出。

    • 什么类型的数据适合放在 Vuex 管理

      至此,我们大概讨论了由于组件化,会产生组件间相互通信数据管理的问题,对此也有相应了的解决办法;然而,并没有一种很好的方式告诉我们到底什么类型的数据适合放在单一的 store 进行管理;回到 Vuex 的定义,将数据使用 Vuex 管理的主要原因之一是解决**组件间的数据共享**。

      所谓共享指的是,同一份数据被多处组件使用,并且要保持一定程度的同步: 
    •