使用 Vue 3 你可能不需要 Vuex
Vuex 是一个非常棒的状态管理库。它简洁易用,并且与 Vue 完美集成。为什么有人会放弃 Vuex?原因可能是即将发布的 Vue 3 版本公开了底层的响应式系统,并引入了构建应用程序的新方法。新的响应式系统非常强大,可以用于集中式状态管理。
您需要共享状态吗?
在某些情况下,多个组件之间的数据流会变得非常困难,以至于需要集中状态管理。这些情况包括:
- 使用相同数据的多个组件
- 具有数据访问的多个根
- 组件深度嵌套
如果以上情况都不成立,那么答案就很简单了,不管你是否需要它。你不需要它。
但是如果你遇到这些情况怎么办?最直接的答案是使用 Vuex。它是一个久经考验的解决方案,效果不错。
但是,如果您不想添加其他依赖项,或者觉得设置过于复杂,该怎么办?新的 Vue 3 版本与 Composition API 结合使用其内置方法可以解决这些问题。
新的解决方案
共享状态必须符合两个标准:
- 反应性:当状态改变时,使用它们的组件也应该更新
- 可用性:可以在任何组件中访问状态
反应性
Vue 3 通过众多函数暴露了其响应式系统。你可以使用reactive
函数(也可以使用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>
可用性
上面的示例对于单个组件来说非常完美,但其他组件无法访问其状态。为了解决这个问题,你可以在 Vue 3 应用程序内部使用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
as 键和一个值传递给该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
。它会将传入的变量封装在一个Proxy
对象中,以防止任何修改(当你尝试修改时会发出警告)。修改可以由可以访问可写存储的单独函数来处理。
import { reactive, readonly } from 'vue';
export const createStore = () => {
const state = reactive({ counter: 0 });
const increment = () => state.counter++;
return { increment, state: readonly(state) };
}
外界只能访问只读状态,只有导出的函数可以修改可写状态。
通过保护状态免受不必要的修改,新的解决方案与 Vuex 相对接近。
概括
通过使用 Vue 3 的反应系统和依赖注入机制,我们从本地状态转变为集中式状态管理,可以在较小的应用程序中取代 Vuex。
我们有一个只读的状态对象,它对模板中的更改具有响应性。该状态只能通过 Vuex 中的 action/mutations 等特定方法进行修改。您可以使用该computed
函数定义其他 getter。
Vuex 具有更多功能,例如模块处理,但有时我们不需要这些功能。
如果您想了解 Vue 3 并尝试这种状态管理方法,请查看我的 Vue 3 游乐场。