vue3学习之Pinia状态管理
状态管理

src/views/Pinia.vue
<script setup> import { ref } from "vue"; import { storeToRefs } from "pinia"; import { useCounterStore } from "../stores/counter"; import { useTodos } from "../stores/todos"; // 可以在组件中的任意位置访问 `store` 变量 const store = useCounterStore(); // const { count, doubleCount } = store; // `count` 和 `doubleCount` 没有响应式 let { count, doubleCount } = storeToRefs(store); // `count` 和 `doubleCount` 是响应式的 ref // 作为 action 的 increment 可以直接解构 const { increment } = store; store.count++; setTimeout(() => { count.value++; }, 2000); setTimeout(() => { increment(); }, 4000); const todoStore = useTodos(); const text = ref(""); function addTodo() { if (text != "") { todoStore.addTodo(text.value); text.value = ""; } } function updateStatus(item) { todoStore.$patch((state) => { for (var i in state.todos) { if (item == state.todos[i]) { state.todos[i]["isFinished"] = !state.todos[i]["isFinished"]; } } }); } function delTodo(item) { let tmp = []; for (var i in todoStore.todos) { if (item != todoStore.todos[i]) { tmp.push(todoStore.todos[i]); } } todoStore.$patch({ todos: tmp }); } todoStore.$subscribe((mutation, state) => { // 每当状态发生变化时,将整个 state 持久化到本地存储。 localStorage.setItem("todos", JSON.stringify(state)); }); </script> <template> <div> <div> <p>count:{{ count }}</p> <p>doubleCount:{{ doubleCount }}</p> <p>store.count:{{ store.count }}</p> <p>store.doubleCount:{{ store.doubleCount }}</p> <!-- 重置 state --> <button @click="store.$reset">重置</button> </div> <div> <p><input v-model="text" placeholder="edit me" @keyup.enter="addTodo" /></p> <ul> <li v-for="item in todoStore.filteredTodos" :key="item.id"> {{ item.text }} <a v-if="item.isFinished">完成</a> <a v-else @click="updateStatus(item)">未完成</a> <a @click="delTodo(item)">删除</a> </li> </ul> <!-- 变更 state --> <button @click="todoStore.$patch({ filter: 'all' })">All</button> <button @click="todoStore.$patch({ filter: 'finished' })">Finished</button> <button @click="todoStore.$patch({ filter: 'unfinished' })">Unfinished</button> <!-- 重置 state --> <button @click="todoStore.$reset">重置</button> </div> </div> </template> <style scoped> span, a { margin-left: 1rem; } a { cursor: pointer; } </style>
src/stores/counter.js
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useCounterStore = defineStore("counter", () => {
const count = ref(0);
function increment() {
count.value++;
}
const doubleCount = computed(() => count.value * 2);
//在 Setup Stores 中,需要创建自己的 $reset() 方法,Option Store不需要手段创建
function $reset() {
count.value = 0;
}
return { count, doubleCount, increment, $reset };
});
src/stores/todos.js
import { defineStore } from "pinia";
export const useTodos = defineStore("todos", {
state: () => ({
/** @type {{ text: string, id: number, isFinished: boolean }[]} */
todos: [],
/** @type {'all' | 'finished' | 'unfinished'} */
filter: "all",
// 类型将自动推断为 number
nextId: 0,
}),
getters: {
finishedTodos(state) {
// 自动补全! ✨
return state.todos.filter((todo) => todo.isFinished);
},
unfinishedTodos(state) {
return state.todos.filter((todo) => !todo.isFinished);
},
/**
* @returns {{ text: string, id: number, isFinished: boolean }[]}
*/
filteredTodos() {
if (this.filter === "finished") {
// 调用其他带有自动补全的 getters ✨
return this.finishedTodos;
} else if (this.filter === "unfinished") {
return this.unfinishedTodos;
}
return this.todos;
},
},
actions: {
// 接受任何数量的参数,返回一个 Promise 或不返回
addTodo(text) {
// 你可以直接变更该状态
this.todos.push({ text, id: this.nextId++, isFinished: false });
},
},
});