译者: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的provide
与inject
:
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。