 Pinia 集中式状态存储
Pinia 集中式状态存储
  # Pinia 集中式状态存储
在现代前端开发中,尤其是在 Vue 3 中,Pinia 提供了一个简洁且功能强大的集中式状态管理解决方案。它被认为是 Vuex 的替代品,具有更简单的 API 和更好的 TypeScript 支持。让我们深入了解 Pinia 如何帮助我们管理全局状态。
# 1. 理解状态
在 Vue 中,状态(State) 是指在应用中需要共享的数据。举个例子,假设你有一个用户登录状态,这个状态在多个页面间共享。一旦用户登录成功,所有的页面都能够读取到当前登录的用户信息。
在 Vue 2 中,我们通常使用 Vuex 来实现集中式状态管理。而在 Vue 3 中,Pinia 是推荐的状态管理库,提供了更简洁、现代的 API。如果你在使用 Vue 2,那么 Vuex 和 Pinia 不能同时使用。
# 2. Vuex 简单示例
Vuex 是 Vue 官方的状态管理库,主要用于 Vue 2.x,但 Vue 3 也支持 Vuex。它的设计理念是集中式存储,所有的状态都存储在单一的 store 中,组件通过 commit 和 dispatch 来修改状态。Vuex 适合需要复杂状态管理和大型应用,但它的 API 相对繁琐,尤其是与 TypeScript 集成时。
让我们先来看看 Vuex 在 Vue 3 中的使用方式。
# 安装 Vuex
npm install vuex@next
# 创建 Vuex Store
// store/index.ts
import { createStore } from 'vuex';
const store = createStore({
  state: {
    username: '--',
  },
  getters: {
    getUsername(state) {
      return state.username.toUpperCase();
    },
  },
  mutations: {
    changeUsername(state, value: string) {
      if (value && value.length < 10) {
        state.username = value;
      }
    },
  },
  actions: {
    changeUsernameAsync({ commit }, value: string) {
      setTimeout(() => {
        commit('changeUsername', value);
      }, 1000);
    },
  },
});
export default store;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 在 Vue 中使用 Vuex
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
const app = createApp(App);
app.use(store);
app.mount('#app');
<!-- App.vue -->
<template>
  <div>
    <h1>Hello {{ username }}</h1>
    <button @click="changeUsername">Change Username</button>
  </div>
</template>
<script lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
export default {
  setup() {
    const store = useStore();
    const username = computed(() => store.getters.getUsername);
    const changeUsername = () => {
      store.dispatch('changeUsernameAsync', 'NewUser');
    };
    return { username, changeUsername };
  },
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 3. 创建 Pinia Store
Store 在 Pinia 中类似于 Vuex 中的 store,它用于保存应用的全局状态。我们可以在创建 Vue 应用时引入 Pinia,或者手动引入。
# 3.1 安装 Pinia
首先,需要安装 Pinia:
npm install pinia
然后,在 main.ts 文件中创建并引入 Pinia:
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
// 创建 Pinia 实例
const pinia = createPinia();
// 使用 Pinia
const app = createApp(App);
app.use(pinia);
app.mount('#app');
2
3
4
5
6
7
8
9
10
11
# 3.2 创建 Store
使用 defineStore 函数来定义一个 Store。Store 中包含三个主要部分:
- state:存储数据,相当于 Vuex 中的 state。
- getter:计算属性,用于获取或计算派生状态,相当于 Vuex 中的 getters。
- action:方法,用于改变 state,处理业务逻辑,相当于 Vuex 中的 actions。
下面是一个创建用户信息管理的例子:
// store/user.ts
import { defineStore } from 'pinia';
export const useUserStore = defineStore('userStore', {
  // state - 用于存储数据
  state: () => ({
    username: '--'
  }),
  // getters - 用于读取计算的值
  getters: {
    getUsername: (state) => state.username.toUpperCase()
  },
  // actions - 用于修改 state 的方法
  actions: {
    changeUsername(value: string) {
      if (value && value.length < 10) {
        this.username = value;
      }
    }
  }
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- state用于存储数据,这里存储了- username。
- getter用于计算并返回- username的大写版本。
- action用于修改- username。
# 3.3 使用 Store 操作数据
Pinia 的使用非常简洁。在 Vue 组件中,我们只需要通过 useUserStore 获取 Store 实例,然后可以通过 state、getter 和 action 来操作数据。
<template>
  <div id="app">
    <h1>Hello {{ userInfo.username }}</h1>
  </div>
</template>
<script lang="ts" setup>
import { useUserStore } from "@/store/user";
// 获取 store
const userStore = useUserStore();
// 直接修改 state
userStore.username = 'Roy';
// 使用 action 修改 state
userStore.changeUsername('Alice');
// 获取 getter
console.log(userStore.getUsername); // 输出:ALICE
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 4. storeToRefs 声明响应式数据
 当你需要在 Vue 模板中访问 Pinia Store 的状态时,可以使用 storeToRefs 来将 Store 中的数据转化为响应式数据。这样做可以确保 Vue 模板能够正确地反应数据的变化。
import { storeToRefs } from 'pinia';
import { useUserStore } from "@/store/user";
// 获取 store
const userStore = useUserStore();
// 使用 storeToRefs 将 store 转为响应式数据
const { username } = storeToRefs(userStore);
console.log(username.value); // 输出 'Roy'
2
3
4
5
6
7
8
9
10
storeToRefs 与 Vue 中的 toRefs 函数类似,但它只会把 store 中的状态部分转为响应式数据,而 toRefs 会将整个对象转为响应式。
# 5. 修改 Store 数据
在实际应用中,通常我们会通过 action 来修改数据,因为它可以确保业务逻辑的一致性。你可以使用 patch 方法直接修改 state,或者使用 action 来修改。
// 通过 action 修改数据
userStore.changeUsername('Roy');
// 直接修改 state
userStore.username = 'Alice';
// 使用 patch 批量修改
userStore.$patch({
  username: 'New User'
});
2
3
4
5
6
7
8
9
10
# 6. Store 的混合式写法
除了传统的对象式 API 外,Pinia 还支持 组合式 API 的写法。这种方式让你可以更灵活地使用 Pinia,尤其是在处理复杂状态管理时。
import { defineStore } from 'pinia';
import { reactive } from 'vue';
// 使用组合式 API 定义 store
export const useUserStore = defineStore('userStore', () => {
  // state
  const userInfo = reactive({ username: '---' });
  // action
  function changeUsername(value: string) {
    if (value && value.length < 10) {
      userInfo.username = value;
    }
  }
  // getter
  function getUsername(): string {
    return userInfo.username.toUpperCase();
  }
  return { userInfo, changeUsername, getUsername };
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在 Vue 组件中使用时,可以直接解构返回的对象:
<script lang="ts" setup>
import { useUserStore } from "@/store/user2";
// 获取 store
const { userInfo, changeUsername, getUsername } = useUserStore();
// 修改 store 数据
changeUsername('Roy');
// 获取 store 数据
console.log(getUsername()); // 输出:ROY
</script>
2
3
4
5
6
7
8
9
10
11
12
# 7. 总结
Pinia 是一个简单且直观的状态管理库,它提供了:
- state用于存储应用的状态。
- getter用于获取计算后的状态。
- action用于修改- state并处理业务逻辑。
它非常适合与 Vue 3 一起使用,相比 Vuex,它的 API 更加简洁,易于使用,且对 TypeScript 支持更好。在大型应用中,Pinia 也能够轻松地扩展和维护状态逻辑。
