Pinia 的安装与基本使用
Pinia 是 Vue 3 推荐的状态管理库,以其轻量、简洁和与 Composition API 的无缝集成受到开发者青睐。本节将详细讲解 Pinia 的安装步骤、基本使用方法,并通过示例展示如何在 Vue 3 项目中创建和管理 Store,帮助你快速上手这一现代状态管理工具。
安装 Pinia
Pinia 的安装过程简单,直接通过包管理器添加即可。
步骤
- 安装 Pinia: 在 Vue 3 项目中运行:
npm install pinia
或使用 Yarn:
yarn add pinia
- 集成到项目: 修改
main.js文件,将 Pinia 注册到应用中:// src/main.js import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; const app = createApp(App); const pinia = createPinia(); app.use(pinia); app.mount('#app');
- 验证:安装完成后,Pinia 已全局可用,组件可以通过
useStore访问 Store。
创建和管理 Store
Pinia 使用 defineStore 函数创建 Store,每个 Store 是一个独立的响应式状态容器。
基本用法
定义 Store
// src/stores/counter.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCounterStore = defineStore('counter', () => {
// 状态
const count = ref(0);
// 方法
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
return { count, increment, decrement };
});
- 解析:
'counter':Store 的唯一标识。- 返回对象:暴露状态和方法。
使用 Store
<!-- src/App.vue -->
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script>
import { useCounterStore } from '@/stores/counter';
export default {
setup() {
const store = useCounterStore();
return {
count: store.count,
increment: store.increment,
decrement: store.decrement
};
}
};
</script>
- 效果:点击按钮,计数增加或减少,页面实时更新。
- 特点:直接访问状态和方法,无需 Mutations。
添加 Getters
Pinia 使用 computed 定义 Getters,派生状态。
// src/stores/counter.js
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const double = computed(() => count.value * 2);
const increment = () => count.value++;
const decrement = () => count.value--;
return { count, double, increment, decrement };
});
使用
<template>
<div>
<p>计数:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="increment">增加</button>
</div>
</template>
<script>
import { useCounterStore } from '@/stores/counter';
export default {
setup() {
const store = useCounterStore();
return { count: store.count, double: store.double, increment: store.increment };
}
};
</script>
- 效果:显示计数及其双倍值,响应式更新。
异步操作
Pinia 的 Actions 是普通函数,支持异步逻辑。
// src/stores/user.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useUserStore = defineStore('user', () => {
const user = ref(null);
const fetchUser = async (id) => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
user.value = await response.json();
};
return { user, fetchUser };
});
使用
<template>
<div>
<button @click="fetchUser(1)">获取用户</button>
<p v-if="user">用户名:{{ user.name }}</p>
</div>
</template>
<script>
import { useUserStore } from '@/stores/user';
export default {
setup() {
const store = useUserStore();
return { user: store.user, fetchUser: store.fetchUser };
}
};
</script>
- 效果:点击按钮异步获取用户数据并显示。
基本操作
1. 修改状态
Pinia 允许直接修改状态:
store.count = 10; // 直接赋值
store.increment(); // 通过方法修改
2. 重置状态
使用 $reset 重置到初始状态:
// 添加 reset 方法
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
});
<template>
<button @click="$reset">重置</button>
</template>
<script>
import { useCounterStore } from '@/stores/counter';
export default {
setup() {
const store = useCounterStore();
return store; // 直接返回整个 store
}
};
</script>
- 限制:
$reset只适用于ref和reactive,复杂对象需手动实现。
3. 订阅状态变化
使用 $subscribe 监听状态变化:
store.$subscribe((mutation, state) => {
console.log('状态变化:', state.count);
});
与 Composition API 集成
Pinia 天然支持 Composition API,可在 setup 中直接使用:
<template>
<p>{{ store.count }}</p>
</template>
<script>
import { useCounterStore } from '@/stores/counter';
export default {
setup() {
const store = useCounterStore();
return { store };
}
};
</script>
- 便捷性:无需额外封装,直接访问响应式状态。
项目结构建议
src/
├── stores/
│ ├── counter.js
│ ├── user.js
│ └── index.js # 可选:统一导出
├── components/
└── main.js
统一导出(可选)
// src/stores/index.js
export * from './counter';
export * from './user';
注意事项
- 唯一 ID:
- 每个
defineStore的 ID 必须全局唯一。
- 每个
- 状态管理范围:
- 小型项目可直接用
ref或reactive,Pinia 更适合中大型应用。
- 小型项目可直接用
- 调试:
- 使用 Vue DevTools 查看和管理 Pinia Store。
综合示例
Store 定义
// src/stores/todo.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useTodoStore = defineStore('todo', () => {
const todos = ref([]);
const addTodo = (text) => {
todos.value.push({ id: Date.now(), text, done: false });
};
const toggleTodo = (id) => {
const todo = todos.value.find(t => t.id === id);
if (todo) todo.done = !todo.done;
};
return { todos, addTodo, toggleTodo };
});
使用
<template>
<div>
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="添加任务" />
<ul>
<li v-for="todo in todos" :key="todo.id" :class="{ done: todo.done }">
<input type="checkbox" v-model="todo.done" @change="toggleTodo(todo.id)" />
{{ todo.text }}
</li>
</ul>
</div>
</template>
<script>
import { useTodoStore } from '@/stores/todo';
export default {
setup() {
const store = useTodoStore();
const newTodo = ref('');
const addTodo = () => {
if (newTodo.value.trim()) {
store.addTodo(newTodo.value);
newTodo.value = '';
}
};
return {
todos: store.todos,
toggleTodo: store.toggleTodo,
newTodo,
addTodo
};
}
};
</script>
<style scoped>
.done { text-decoration: line-through; }
</style>
- 效果:添加任务并切换完成状态,列表实时更新。
总结
Pinia 的安装和使用非常直观,通过 defineStore 创建 Store,结合 ref 和 computed 管理状态和派生数据。其简洁的 API 和对 Composition API 的支持使其成为 Vue 3 的首选状态管理工具。掌握本节内容后,你可以轻松在项目中应用 Pinia。下一节将探讨模块化状态管理,进一步提升你的技能!
