940 字
约 3 分钟
0
Pinia 入门:Vue 3 官方推荐的状态管理

Pinia 入门:Vue 3 官方推荐的状态管理

多个组件要共享一份数据时,props 层层传递会变成噩梦。Pinia 就是 Vue 3 时代的标准答案。

为什么需要状态管理

一个典型场景:登录用户的头像和昵称,顶栏要显示、评论区要显示、设置页要修改。如果用 props 一层层传,组件树就成了数据的中转站;如果各组件自己发请求拉,又会出现「改了这里那里没同步」。

状态管理的思路是:把共享数据从组件树里抽出来,放一个全局仓库(store)。组件用的时候去仓库取,改的时候改仓库,所有用到这份数据的地方自动更新。

Vue 2 时代答案是 Vuex,Vue 3 时代官方推荐 Pinia——它把 Vuex 里的 mutation、模块嵌套这些繁琐概念全砍了,剩下的 API 就是「定义仓库、读、写」。

五分钟上手

pnpm add pinia
import { createPinia } from 'pinia';
const pinia = createPinia();
app.use(pinia);   // main.ts 里注册

定义一个仓库:

// stores/user.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export const useUserStore = defineStore('user', () => {
  // state:响应式数据
  const nickname = ref('');
  const avatar = ref('');

  // getter:计算属性
  const hasLogin = computed(() => nickname.value !== '');

  // action:修改逻辑(支持异步)
  async function fetchProfile() {
    const res = await fetchUserProfile();
    nickname.value = res.nickname;
    avatar.value = res.avatar;
  }

  function logout() {
    nickname.value = '';
    avatar.value = '';
  }

  return { nickname, avatar, hasLogin, fetchProfile, logout };
});

组件里用:

<script setup>
import { useUserStore } from '@/stores/user';
import { storeToRefs } from 'pinia';

const store = useUserStore();
// 解构响应式数据必须用 storeToRefs,否则丢失响应性
const { nickname, hasLogin } = storeToRefs(store);
// action 直接解构没问题
const { logout } = store;
</script>

<template>
  <div v-if="hasLogin">你好,{{ nickname }}</div>
</template>

注意那个最经典的坑:解构 state 要用 storeToRefs。直接 const { nickname } = store 拿到的是快照值,之后仓库变了视图不会更新。

Setup 语法的两个语法糖

上面的写法是 Setup Store(函数式定义),和 Vue 3 组合式 API 心智完全一致,这是 Pinia 相对 Vuex 最大的体验提升。还有两个实用 API:

watch 监听仓库变化:

store.$subscribe((mutation, state) => {
  localStorage.setItem('user', JSON.stringify(state));   // 每次变化自动持久化
});

patch 批量修改:

store.$patch({ nickname: '新昵称', avatar: 'new.png' });   // 一次改动,一次触发

本站管理后台用 Pinia 管登录态和菜单状态,配合 pinia-plugin-persistedstate 插件做持久化——刷新页面登录态不丢,就是 $subscribe 持久化的官方化封装。

持久化:一行配置

import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

pinia.use(piniaPluginPersistedstate);

// 仓库定义处加一行
export const useUserStore = defineStore('user', () => { ... }, {
  persist: true,    // state 自动同步到 localStorage
});

什么时候该建 store

一个实用的判断标准:这份状态是否有两个以上不相邻的组件需要。是,进 store;只有一个组件树分支用,props/emit 足够;只有单个组件内部用,ref 就好。

反模式也要警惕:把整个页面状态全塞 store,等于把组件逻辑搬了个家,还失去了组件的独立复用性。store 放「跨组件共享的真状态」,组件内放「自己的局部状态」,边界清晰才好维护。

小结

Pinia 的成功在于做减法:没有 mutation、没有模块嵌套、原生支持组合式 API 和 TypeScript 推断。定义仓库 = 一个函数,读 = 解构,写 = 改 ref 或调 action,五个概念就能覆盖全部日常。从 Vuex 迁移或从零开始,它都是 Vue 3 项目的默认选择。

Pinia 入门:Vue 3 官方推荐的状态管理
http://www.clxhxhhr.top/posts/3714/
作者
clxstart
发布于
2026-09-25
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。