Vue

Vue状态管理

Vue状态管理方法解析

Posted by Starrynight on 2024-07-12
Estimated Reading Time 5 Minutes
Words 1.2k In Total
Viewed Times

Vue状态管理

在 Vue 3 中,状态管理主要有两种方式:

  1. 组合式 API (Composition API) + reactive() / ref()(适用于小型应用)
  2. Pinia(推荐替代 Vuex,适用于中大型应用)

1. 组合式 API 的状态管理

Vue 3 自带的 reactive()ref() 使得我们可以在组件间共享状态,适用于 小型应用或简单的状态管理

(1)使用 reactive() 创建响应式对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
import { reactive } from 'vue';

const state = reactive({
count: 0
});

const increment = () => {
state.count++;
};
</script>

<template>
<p>计数:{{ state.count }}</p>
<button @click="increment">增加</button>
</template>

📌 特点:

  • reactive() 只能用于 对象,返回的是深层响应式对象。
  • 访问属性时需要 state.count,不能直接 state

(2)使用 ref() 创建基本数据类型的响应式状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup>
import { ref } from 'vue';

const count = ref(0);

const increment = () => {
count.value++;
};
</script>

<template>
<p>计数:{{ count }}</p>
<button @click="increment">增加</button>
</template>

📌 特点:

  • ref() 可以用于 基本数据类型(number、string、boolean)
  • 访问和修改时必须使用 .value,如 count.value++

(3)跨组件共享状态

在 Vue 3 中,我们可以使用 单独的模块 进行状态管理。

创建 store.js(用于共享状态)

1
2
3
4
5
import { reactive } from 'vue';

export const store = reactive({
count: 0
});

A.vue 中使用

1
2
3
4
5
6
7
8
<script setup>
import { store } from '../store';
</script>

<template>
<p>A 组件计数:{{ store.count }}</p>
<button @click="store.count++">增加</button>
</template>

B.vue 中使用

1
2
3
4
5
6
7
<script setup>
import { store } from '../store';
</script>

<template>
<p>B 组件计数:{{ store.count }}</p>
</template>

📌 特点:

  • store 在多个组件中共享,A.vue 组件修改 count 后,B.vue 也会同步更新。

2. 使用 Pinia 进行状态管理

在中大型应用中,推荐使用 Pinia 作为 Vue 3 的官方状态管理库(Vuex 已被 Pinia 取代)。

(1)安装 Pinia

1
2
3
yarn add pinia
# 或
npm install pinia

(2)创建 store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++;
}
}
});

📌 说明:

  • defineStore('counter', { ... }) 定义一个名为 counter 的状态管理模块。
  • state 用于存储数据。
  • actions 用于定义 修改 state 的方法(类似 Vuex 的 mutations + actions)。

(3)在 Vue 组件中使用 Pinia

main.js 中注册 Pinia

1
2
3
4
5
6
7
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';

const app = createApp(App);
app.use(createPinia()); // 安装 Pinia
app.mount('#app');

Counter.vue 组件中使用 Pinia

1
2
3
4
5
6
7
8
9
10
<script setup>
import { useCounterStore } from '../store/index';

const counter = useCounterStore();
</script>

<template>
<p>计数:{{ counter.count }}</p>
<button @click="counter.increment">增加</button>
</template>

📌 特点:

  • 直接通过 counter.count 访问状态。
  • 通过 counter.increment() 修改状态。

(4)使用 getters 计算属性

有时,我们希望基于 state 计算派生状态,可以使用 getters

修改 store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
}
}
});

Counter.vue 中使用 getters

1
2
3
4
5
6
7
8
9
10
11
<template>
<p>计数:{{ counter.count }}</p>
<p>两倍计数:{{ counter.doubleCount }}</p>
<button @click="counter.increment">增加</button>
</template>

<script setup>
import { useCounterStore } from '../store/index';

const counter = useCounterStore();
</script>

📌 特点:

  • doubleCount 作为计算属性,无需手动更新,count 变化时自动更新。

(5)Pinia 持久化存储

Pinia 默认状态存储在内存中,刷新后会丢失。我们可以使用 pinia-plugin-persistedstate 进行持久化存储。

安装插件

1
yarn add pinia-plugin-persistedstate

修改 store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++;
}
},
persist: true // 让 Pinia 状态持久化
});

📌 特点:

  • persist: true 会自动将状态存储在 localStorage 中,页面刷新后状态不会丢失。

总结

方案 适用场景 主要 API
Vue 3 reactive() / ref() 适用于小型应用或简单状态管理 reactive()ref()computed()
Pinia 适用于中大型应用,推荐替代 Vuex defineStore()useStore()actionsgetters
Vuex(不推荐) Vue 2 时代的状态管理库,Vue 3 已不推荐 createStore()

在 Vue 3 中,Pinia 是最推荐的状态管理方案,结合 Composition API 使得代码更加简洁和高效。🚀


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !