阅读 2163

【译】为什么不需要在Vue3中使用Vuex

原文地址medium.com/better-prog…

译者:Gavin,未经授权禁止转载。

前言

Vuex是一个很棒的状态管理库,它简单易懂,且与Vue集成良好。为什么不直接使用Vuex?因为即将发布的Vue3公开了底层的响应式系统,并引入了构建应用程序的新方法。新的响应式系统功能强大,可用于共享状态管理。

你需要一个共享状态吗?

在某些情况下,多个组件之间数据共享困难,以至于需要集中的状态管理。情况包括:

  • 多个组件使用相同数据
  • 多个根模块需要单独接入数据
  • 深层嵌套的组件需要与其它组件进行数据通讯

如果上述情况都不存在,那么很容易做决定:你不需要它。

如果存在上述情况呢?最直接的答案就是使用Vuex,这是一个经过实战检验的解决方案,而且效果不错。

如果不想添加另一个依赖项或者不想做过多的配置?那么现在就可以与Composition API一起,用新的Vue3内置的方法解决这些问题。

新的解决方案

共享状态必须符合两个标准:

  • 响应式:当状态改变时,使用它们的组件也相应更新
  • 可用性:可以在任何组件中访问

响应式

Vue3对外暴露了其响应式系统的众多函数,你可以使用reactive函数创建一个reactive变量(也可以使用ref函数)

import { reactive } from 'vue';

export const state = reactive({ counter: 0 });
复制代码

从响应式函数返回的对象是一个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>
复制代码

可用性

上面的示例非常适合单个组件,但多组件共享状态就不适用了。为了克服这个问题,你可以使用Vue3的provideinject

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名称。

如上图,如果你在最上层的组件上提供值,那么它将在所有组件中都可用,或者你也可以在应用的主文件上调用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函数包装状态,使其成为受保护的状态,需要修改状态时通过单独的函数来处理。

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。

我们有一个只读的状态对象,并且会对templates中的更改作出响应。这种状态只能通过特定的方法修改,类似Vuex的actions/mutations,你可以使用computed函数定义其它getter。