1、Pinia 介绍
Pinia
是一个 状态管理工具,为 Vue 应用程序提供共享状态管理能力。
命名由来:和 菠萝 一样 香。
语法和 Vue3
一样,它实现状态管理有两种语法:选项式API 与 组合式API。
它也支持 Vue2
也支持 devtools
,也支持 TS
。
优势:
- 可以 创建多个全局仓库,不用像 Vuex 一个仓库嵌套模块,结构复杂;
- 管理数据简单,提供数据和修改数据的逻辑即可,不像
Vuex
需要记忆太多的API。
2、上手教程
安装 Pinia
命令:
npm i pinia
导入 Pinia
并实例化:
import { createApp } from "vue";
import { createPinia } from "pinia"; //✅新增
import App from "./App.vue";
const pinia = createPinia(); //✅新增
const app = createApp(App);
app.use(pinia); //✅新增
app.mount("#app");
新建 src/store/counter.ts
:
import { defineStore } from "pinia"
import { computed, ref } from "vue"
export const useCounterStore = defineStore("counter", () => {
// state
const count = ref(100)
// getters
const doubleCount = computed(() => count.value * 2)
// mutations
const update = () => count.value++
// actions
const asyncUpdate = () => {
setTimeout(() => {
count.value++
}, 1000)
}
return { count, doubleCount, update, asyncUpdate }
})
在组件内使用 store
的状态:
<script setup lang="ts">
import { useCounterStore } from "../store/channel";
const store = useCounterStore();
</script>
<template>
APP {{ store.count }} {{ store.doubleCount }}
<button @click="store.update()">count++</button>
<button @click="store.asyncUpdate()">async update</button>
</template>
3、storeToRefs
使用 storeToRefs
解决 解构 仓库状态丢失响应式的问题。
import { storeToRefs } from 'pinia'
const store = useCounterStore()
const { count, doubleCount } = storeToRefs(store)
4、使用 Pinia 改造头条
安装 pinia
和使用 pinia
插件(此步参考前面点2)
src/store/channel.ts
import { defineStore } from "pinia";
import { ref } from "vue";
export const useChannelStore = defineStore("channel", () => {
const channelId = ref(0);
const changeChannel = (id: number) => {
channelId.value = id;
};
return { channelId, changeChannel };
});
App.vue
<script setup lang="ts">
import ChannelNav from "./components/ChannelNav.vue";
import ArticleList from "./components/ArticleList.vue";
</script>
<template>
<ChannelNav />
<ArticleList />
</template>
src/components/ChannelNav.vue
<script setup lang="ts">
....
import { useChannelStore } from "../store/channel";
const store = useChannelStore();
....
</script>
<template>
<div class="channel-nav">
<nav class="list">
<a
....
:class="{ active: store.channelId === item.id }"
@click="store.changeChannel(item.id)"
>
{{ item.name }}
</a>
</nav>
</div>
</template>
src/components/ArticleList.vue
<script setup lang="ts">
....
import { useChannelStore } from "../store/channel";
const store = useChannelStore();
....
watch(
() => store.channelId,
....
);
</script>