vue3-pinia

好的!这份笔记专为你整理,涵盖了 Pinia 的核心知识点、实战写法和避坑指南。内容尽量精简结构化,方便你直接复制保存,随时查阅。


📦 Pinia 核心知识笔记(Vue 3 专用)

一句话概括 :Pinia 是 Vue 的官方状态管理库,用于在不同组件之间共享响应式数据(相当于前端内存里的全局数据库)。


1. 核心概念(三大支柱)

概念 作用 类比 Java / 后端
State(状态) 存储共享的数据 类的成员变量(属性)
Getters(计算属性) 基于 State 派生出新数据(类似 Vue 的 computed) 类的 getter 方法(如 getFullName)
Actions(动作) 修改 State 的方法(支持异步) 类的 setter 或 service 方法

2. 如何定义一个 Store(两种写法)

✅ 写法一:选项式(Options Store)------ 适合传统习惯

复制代码
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    name: 'Vue'
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++; // 注意:在 actions 里用 this 访问 state
    },
    async fetchCount() {
      // 支持异步
      const res = await api.getCount();
      this.count = res.data;
    }
  }
});

✅ 写法二:组合式 API(Setup Store)------ 推荐写法(你目前学的)

复制代码
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export const useUserStore = defineStore('user', () => {
  // 1. State(用 ref 定义响应式数据)
  const list = ref<User[]>([]);
  const loading = ref(false);

  // 2. Getters(用 computed 定义)
  const totalCount = computed(() => list.value.length);

  // 3. Actions(用普通函数定义)
  const setList = (newList: User[]) => {
    list.value = newList;
  };

  // 4. 将需要暴露的内容返回出去
  return { list, loading, totalCount, setList };
});

区别 :选项式用 this,组合式用 ref/computed 并直接 return。组合式更灵活,且 TypeScript 类型推导更好。


3. 在组件中使用 Store(⚠️ 重点:响应性丢失问题)

❌ 错误写法(解构会丢失响应性)

复制代码
const { list, setList } = useUserStore();
// list 变成了普通值,修改后页面不会更新!

✅ 正确写法 1:直接使用 store 对象

复制代码
const store = useUserStore();
// 模板中直接用 store.list,方法用 store.setList

✅ 正确写法 2:使用 storeToRefs 解构(保持响应性)

复制代码
import { storeToRefs } from 'pinia';

const store = useUserStore();
// 只能解构 state 和 getters(用 storeToRefs)
const { list, totalCount } = storeToRefs(store);
// actions 可以直接解构(不需要包起来)
const { setList } = store;

// 此时 list 和 totalCount 依然是响应式的!

4. 修改 State 的四种方式(由简到繁)

方式 代码示例 适用场景
1. 直接修改 store.list = [...] 简单赋值
2. 通过 Actions store.setList([...]) 推荐! 逻辑复用,便于调试
3. $patch 批量修改 store.$patch({ count: 1, name: 'hi' }) 同时改多个字段
4. $patch 函数式修改 store.$patch((state) => { state.count++ }) 复杂逻辑批量改

最佳实践 :所有修改尽量封装在 actions 里,避免业务逻辑散落在各个组件中。


5. Getters(派生状态)详解

复制代码
// 在 store 里定义
const filteredList = computed(() => {
  return list.value.filter(item => item.name.includes('张'));
});

// 在组件里使用(配合 storeToRefs 解构或直接 store.filteredList)
const { filteredList } = storeToRefs(store);

特点:Getter 会根据依赖自动缓存,只有依赖变化时才重新计算。


6. Actions(处理异步请求)------ 配合你的 Axios

复制代码
// store 里定义
const fetchUsers = async () => {
  loading.value = true;
  try {
    const res = await getUserList(); // 你封装的 Axios 方法
    list.value = res;
  } catch (error) {
    console.error('加载失败', error);
  } finally {
    loading.value = false;
  }
};

// 在组件里调用
await store.fetchUsers();

7. 跨 Store 通信(一个 Store 引用另一个)

复制代码
import { useUserStore } from './user';

export const useOrderStore = defineStore('order', () => {
  const userStore = useUserStore(); // 直接引入其他 Store

  const currentUser = computed(() => {
    // 拿到用户列表里的第一个
    return userStore.list[0];
  });

  return { currentUser };
});

8. 数据持久化(刷新页面数据丢失怎么办?)

Pinia 默认存在内存中,页面刷新就没了。通常配合插件 pinia-plugin-persistedstate:

复制代码
npm i pinia-plugin-persistedstate

// main.ts 中配置
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

// 在 store 中开启持久化
export const useUserStore = defineStore('user', () => {
  // ...
}, {
  persist: true // 自动存 localStorage
});

9. 在 Vue Router(路由守卫)中使用 Pinia

注意:在路由守卫中不能直接用 useUserStore()(因为 Pinia 还没激活)。要在 router 文件里这样写:

复制代码
// router/index.ts
router.beforeEach((to) => {
  // 确保 Pinia 已激活(Vue 应用已挂载)
  const userStore = useUserStore(); 
  if (to.meta.requiresAuth && !userStore.isLoggedIn) {
    return '/login';
  }
});

10. Vue Devtools 调试

Pinia 默认集成 Vue Devtools,在浏览器插件中可以:

  • 查看所有 Store 的当前 State。
  • 回放 Actions 的历史记录(时间旅行调试)。

🚀 速查速记口诀

  1. 定义仓库 :defineStore('id', () => { ... })
  2. 定义数据 :ref() / reactive() 包起来
  3. 定义计算 :computed() 返回派生值
  4. 定义方法 :普通函数,操作 value
  5. 暴露出去 :return { data, method }
  6. 组件使用 :const store = useXxxStore()
  7. 解构数据 :必须用 storeToRefs(store),方法不用
  8. 改数据:优先用 Actions,别到处直接改

这份笔记覆盖了 Pinia 95% 的日常开发场景。刚开始学可以先照着"组合式 API"的模板写,遇到复杂需求再回来看高级用法。祝学习顺利!😊

相关推荐
y = xⁿ10 小时前
关于Agent工程落地
前端·人工智能·python
web打印社区10 小时前
JS 静默打印怎么做:纯前端为什么不行,以及最小可跑通写法
开发语言·前端·javascript·websocket·网络协议·http·pdf
web打印社区10 小时前
HTML5 静默打印:前端页面怎么调用打印机且尽量不弹窗
前端·javascript·vue.js·pdf·html·html5
Python大数据分析10 小时前
开源免费、AI 驱动的 Web 打印设计器 OpenPrint:从拖拽设计到 ERP 对接全流程实战
前端·人工智能·开源
溪语流沙10 小时前
【每天一个CSS | Day11】赛博朋克故障风文字:红青分离 + 切片抖动
前端·css
liangshanbo121511 小时前
React Fiber:从“解决卡顿”到完整更新链路
前端·javascript·react.js
Timmy11 小时前
前端转全栈笔记:讲框架之前,先把 TypeScript 这关过了
前端·人工智能·node.js
计算机魔术师11 小时前
年收入650亿、亏420亿,Anthropic凭什么敢叫价万亿?
前端
Frag0ut11 小时前
Chrome Canary 最新实验功能:AI Mode、按设备筛选历史记录与 Gemini 自动改密
前端·人工智能·chrome·dev·beta·canary·最新实验功能
雪芽蓝域zzs11 小时前
第3节:el-select 弹窗定位、滚动穿透与挂载容器(popper-append-to-body /teleported)
vue.js·elementui