Vuex 之外的存储数据替代方案

既然说 Vuex 有那么些的缺点,那么当我们判断其并非最佳方案时有哪些替代品呢?

4-1. 向下传递的 props

往往最简单的方法就是最好的方法。如果能用从父组件向子组件传递的 props 解决问题,你就绝对应该那么干。

4-2. provide / inject

一个少有人知的 Vue.js 特性是 provide / inject。它用于需要从一个祖先组件向其所有子孙组件传递数据的场景。

官方文档中的基础示例:

// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}
 
// 子孙组件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

一个典型的例子是 accordion 组件,可能由一个主要的 AppAccordion 组件、表示每个折叠项的若干 AppAccordionItem 子组件,及表示折叠项主体的 AppAccordionBody 孙组件组成。provide / inject 使得从主组件向孙组件传递数据成为可能。在各级组件直接互相依赖的情形下(AppAccordionBody 在脱离 AppAccordion 组件的情况下无法使用),这种模式比起使用 Vuex 来简单又高效。

4-3. 从 API / Apollo 获取数据

让我们回顾一个 2-2 中提及的 Vuex 正面例证:有着多个分类的 To-Do 应用。其实相比于一次性获取并存储一个用户所有(未完成的)To-Do 项,更好的一种实现可能是只获取开头的 20 条用于入口页面的渲染。若用户导航到了特定分类页面,则触发一次新的请求,以从 API 中获取对应分类的开头 20 条。如果用户访问了之前打开过的分类,我们既可以重新请求一次新鲜的数据,也可以实现某种缓存(Apollo 就提供了开箱即用的缓存机制)。

译注:GraphQL 是由 Facebook 创造的用于描述复杂数据模型的一种查询语言,是一种用于前后端数据查询方式的规范。Apollo 是基于 GraphQL 的全栈解决方案集合。从后端到前端提供了对应的 lib 使得开发使用 GraphQL 更加的方便;一个可用于 Vue 的插件是 vue-apollo.netlify.com/

4-4. portals

乍一看,PortalVue 插件貌似和状态管理怎么也扯不上关系。但有些状况下一个 portal 可以直接访问组件的状态,而不用通过集中式的 store。一种典型的例子可能是个 modal 对话框,用来确认用户不是误触了删除按钮:

<template>
  <button class="AppDeleteButton" @click="modal = true">
    删除
    <portal to="modals" v-if="modal">
      <app-modal>
        你可想好了啊?
        <button @click="delete(item.id)">对</button>
        <button>算了</button>
      </app-modal>
    </portal>
  </button>
</template>

可见当 AppDeleteButton 组件被点击时,就显示其包含的 modal。相比于不使用 ProtalVue 插件时要分离书写按钮和弹窗并通过 store 全局访问 id 数据,例子中这种方式就能直接在 model 组件中访问 AppDeleteButton 的内部属性值了。

决策图