一、pinia
Pinia 是 Vue 的存储库,它允许跨组件/页面共享状态。
与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。
二、引入pinia
安装:
npm i pinia
main.ts中引入pinia:
import { createPinia } from 'pinia'
app.use(createPinia())
三、定义store:defineStore()
定义store需要使用pinia自带的defineStore()方法,第一个参数为该store的名称:
在根目录创建:./stores/count.ts文件:
import { defineStore } from "pinia";
export const useCounterStore = defineStore('count',{
state: () => ({
counter: 1,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
actions: {
increment() {
this.counter++;
},
},
});
四、使用store
直接使用store.xxx数据无响应式,
为了store中的数据有响应式,需使用storeToRefs()方法对store进行解构。
<template>
<div class="about">
<h1>{{ storeCounter }}</h1>
<h1>{{ counter }}</h1>
<h1>{{ doubleCount }}</h1>
</div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { computed } from "vue";
import { useCounterStore } from "../stores/counter";
const store = useCounterStore();
const storeCounter = store.counter; // 非响应式
const { counter } = storeToRefs(store); // 响应式
setTimeout(() => {
store.counter++;
}, 3000);
</script>
五、改变state数据
1. store.xxx直接修改
store.xxx直接修改一次只能改变state中一个数据值。
2. 使用$patch()方法修改
使用store.$patch()方法修改:一次可改变state中多个数据值。
<template>
<div class="about">
<h1>{{ storeCounter }}</h1>
<h1>{{ counter }}</h1>
<div @click="click">{{ name }}</div>
</div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { computed } from "vue";
import { useCounterStore } from "../stores/counter";
const store = useCounterStore();
const storeCounter = store.counter; // 非响应式
const { counter, name } = storeToRefs(store); // 响应式
const click = () => {
store.$patch({
counter: store.counter + 1,
name: "John",
});
};
</script>
六、getter
1. 设置getter:
import { defineStore } from "pinia";
export const useCounterStore = defineStore('main',{
state: () => ({
counter: 1,
name: 'Amy'
}),
getters: {
doubleCount: (state) => state.counter * 2, // 由于没有使用this,会自动进行类型推断
doubleCountOne(): number { // 这里需要设置类型
return this.counter * 2 + 1
},
}
});
使用:
<template>
<div class="about">
<h1>{{ doubleCount }}</h1>
<h1>{{ doubleCountOne }}</h1>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useCounterStore } from "../stores/counter";
const store = useCounterStore();
const doubleCount = computed(() => store.doubleCount);
const doubleCountOne = computed(() => store.doubleCountOne);
</script>
2. 设置参数
import { defineStore } from "pinia";
export const useCounterStore = defineStore('main',{
state: () => ({
counter: 1
}),
getters: {
countTwo: (state) => (num: number) => state.counter * num,
}
});
使用:
<template>
<div class="about">
<h1>{{ countTwo(3) }}</h1>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useCounterStore } from "../stores/counter";
const store = useCounterStore();
const countTwo = computed(() => store.countTwo);
</script>
3. 访问其他 Store 的getter
新建./stores/user.ts:
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state:()=> ({
userId: '1134374872347'
})
})
./store/count.ts中获取user.ts中的userId:
import { defineStore } from "pinia";
import { useUserStore } from './user'
export const useCounterStore = defineStore('main',{
getters: {
otherStoreMsg: () => {
const userStore = useUserStore()
return userStore.userId
}
}
});
七、action
设置action:
import { defineStore } from "pinia";
import {useUserStore} from './user'
export const useCounterStore = defineStore('main',{
state: () => ({
counter: 1,
}),
actions: {
increment() {
this.counter++;
},
},
});
使用:
<template>
<div class="about">
<div @click="click">{{ counter }}</div>
</div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { useCounterStore } from "../stores/counter";
const store = useCounterStore();
const { counter } = storeToRefs(store); // 响应式
const click = () => {
store.increment();
};
</script>