你可能不需要Vuex

888 阅读4分钟
本文为中文翻译,[原文在这里](https://dev.to/blacksonic/you-might-not-need-vuex-with-vue-3-52e4)

Vuex是一个很棒的状态管理库。它很简单并且非常好的与Vue集成。为什么有人要弃用Vuex?原因可能是即将到来的Vue3暴露出了reactivity系统,这是一种新的方案去组织你的应用。新的reactivity系统非常的强大,它可以被用来中心化状态管理。

你需要共享状态么?

在一些场景,多组件中的数据流你很难做中心化的状态管理,这些场景包括:

  • 多个组件使用一样的数据
  • 多个根节点的数据访问
  • 深嵌套的组件

如果以上的场景你都没有遇到,那么答案是显而易见的,不管你需要Vuex与否,你都不需要。

但是当你遇到了这些场景,最直截了当的回答是使用Vuex。它是久经考验的解决方案,而且做的很好。

你不想添加其他三方依赖或者发现Vuex的方案过于复杂?新的Vue3版本,可以使用composition-api中的内置方法解决这些问题。

新的方案

共享状态方案必须符合两种标准:

  • 响应式:当共享状态改变,组件中使用到的部分也需要更新。
  • 高可用性:共享状态可以在任意的组件中访问到。

响应式

Vue3通过众多的函数暴露出了它的响应式系统。你可以使用reactivity函数创建一个响应式的变量(一些场景需要ref函数)。

import { reactive } from 'vue';

export const state = reactive({ counter: 0 });

这个reactive函数返回的对象是一个Proxy对象,它可以追踪自身属性的变化。当在组件中的模版使用时,组件会依据响应式数据的变化重新渲染。

<template>
  <div>{{ state.counter }}</div>
  <button type="button" @click="state.counter++">Increment</button>
</template>

<script>
  import { reactive } from 'vue';

  export default {
    setup() {
      const state = reactive({ counter: 0 });
      return { state };
    }
  };
</script>

高可用性

以上的例子对于单组件来说非常的好用,但是其他的组件无法访问到状态。为了解决这个问题,你可以通过provideinject方法在Vue3应用的内部创建可用性的值。

import { reactive, provide, inject } from 'vue';

export const stateSymbol = Symbol('state');
export const createState = () => reactive({ counter: 0 });

export const useState = () => inject(stateSymbol);
export const provideState = () => provide(
  stateSymbol, 
  createState()
);

当你使用Symbol类型键值传给provide方法,这个值便可以在任意的子组件中通过inject方法被使用。使用Symbol类型的键名会被用于检索对应的值。

通过这种方案,如果你是在最顶层组件提供值,它将可以在所有组件中使用。或者,你可以在应用实例入口main中使用provide

import { createApp, reactive } from 'vue';
import App from './App.vue';
import { stateSymbol, createState } from './store';

const app = createApp(App);
app.provide(stateSymbol, createState());
app.mount('#app');
<script>
  import { useState } from './state';

  export default {
    setup() {
      return { state: useState() };
    }
  };
</script>

改进它

以上的方案可以使用,但是有一个缺陷:你不知道谁更改了谁。状态可以被直接更改,没有任何的限制。

你可以使用readonly函数保护我们的状态。它可以被用于阻止任何对Proxy变量对象的更改(在你更改时会触发警告)。状态的变更应该抽象出一些有权限的函数来管理。

import { reactive, readonly } from 'vue';

export const createStore = () => {
  const state = reactive({ counter: 0 });
  const increment = () => state.counter++;

  return { increment, state: readonly(state) };
}

这样外部只能够访问到可读的状态,我们仅仅暴露出一些函数去做状态的改变。

拥有状态更改保护的新方案更加的接近Vuex。

总结

通过使用Vue3中的响应式系统和依赖注入机制,我们已经解决了本地中性化状态管理,这种方案可以在一些小应用中代替Vuex。

我们有一个仅可读状态对象,而且在模版中是响应式的。这个状态仅可以通过特殊的函数改变,像Vuex中的action/mutations一样。你也可以通过computed函数自定义一个getters。

Vuex还有更多的功能如模块管理等,有时候我们不需要这些。

如果你想要预览一下Vue3,想要尝试一下这个状态管理方案,可以查看我的github仓库