Pinia初始化
- 创建
VUE3
项目
npm init vite @latest
- 安装
Pinia
npm install pinia
-
将
Pinia
挂载到vue
实例main.ts
import {createApp} from 'vue'
import App from './App.vue'
import {createPinia} from "pinia";
createApp(App)
.use(createPinia())
.mount('#app')
- 在
src
目录下新建story/index.ts
并配置
import {defineStore} from "pinia";
export const useMainStore = defineStore('main', {
state: () => {
return {}
},
getters: {},
actions: {}
})
参数说明:
defineStore(容器唯一标识(会将其挂载到根容器),参数选项)
state:存储全局状态
getters:封装计算属性 具有缓存功能
actions:封装业务逻辑 修改state
测试Pinia是否可用
- 配置
index.ts
import {defineStore} from "pinia";
export const useMainStore = defineStore('main', {
state: () => {
return {
testPinia: '欢迎使用Pinia'
}
},
getters: {},
actions: {}
})
- 编写
TestPinia.vue
<template>
</template>
<script setup lang="ts">
import {useMainStore} from "./";
const mainStory = useMainStore()
console.log(mainStory.testPinia)
</script>
<style scoped>
</style>
- 编写
App.vue
<script setup lang='ts'>
import TestPinia from './components/TestPinia.vue';
</script>
<template>
<TestPinia/>
</template>
<style>
</style>
- 测试结果
通过解构访问Pinia数据
为什么要解构使用?
由于在模板中使用pinia
数据时,需要通过容器对象来拿到数据十分繁琐
所以将数据通过解构的方式使其只需要通过参数名就能直接拿到对应的值
- 未解构前
TestPinia.vue
<template>
<h1>未解构</h1>
<p>显示内容1:{{ mainStory.testPinia1 }}</p>
<p>显示内容2:{{ mainStory.testPinia2 }}</p>
<hr/>
<h1>解构后</h1>
<p>显示内容1:{{ testPinia1 }}</p>
<p>显示内容2:{{ testPinia2 }}</p>
<hr/>
<button @click="updateData">修改内容</button>
</template>
<script setup lang="ts">
import {useMainStore} from '../story';
const mainStory = useMainStore()
console.log(mainStory.testPinia)
/*解构语句*/
const {testPinia1, testPinia2} = mainStory
const updateData = () => {
mainStory.testPinia1 = '修改成功';
}
</script>
<style scoped>
</style>
index.ts
import {defineStore} from "pinia";
export const useMainStore = defineStore('main', {
state: () => {
return {
testPinia: '欢迎使用Pinia',
testPinia1: '欢迎使用Pinia1',
testPinia2: '欢迎使用Pinia2'
}
},
getters: {},
actions: {}
})
结果:
存在问题:
使用解构的方式拿到的数据不是响应式的,而是一次性的
也就是当数据发生改变时不会自动改变
例如:当点击修改后,只有未解构的内容发改变,而结构后的不会改变
如何解决解构内容不更新问题?
使用Pinia
官方APIstoreToRefs
解决
storeToRefs:
将结构出来的数据用ref来代理响应式
<template>
<h1>未解构</h1>
<p>显示内容1:{{ mainStory.testPinia1 }}</p>
<p>显示内容2:{{ mainStory.testPinia2 }}</p>
<hr/>
<h1>解构后</h1>
<p>显示内容1:{{ testPinia1 }}</p>
<p>显示内容2:{{ testPinia2 }}</p>
<hr/>
<button @click="updateData">修改内容</button>
</template>
<script setup lang="ts">
import {useMainStore} from '../story';
import {storeToRefs} from "pinia";
const mainStory = useMainStore()
/*修改后的解构语句*/
const {testPinia1, testPinia2} = storeToRefs(mainStory)
const updateData = () => {
mainStory.testPinia1 = '修改成功';
}
</script>
<style scoped>
</style>
此时在单击修改按钮时,都发生了改变:
状态更新及action
- 方式一:直接赋值更新
mainStory.testPinia1 = '已更新';
- 方式二:使用$patch更新多个数据 批量更新
mainStory.$patch({
testPinia1: '已更新1',
testPinia2: '已更新2',
})
- 方法三:直接拿到 state进行修改 批量
mainStory.$patch(state => {
state.testArr.push(4)
})
- 方式四:封装到action中使用(可以手动传参)
import {defineStore} from "pinia";
export const useMainStore = defineStore('main', {
state: () => {
return {
testPinia: '欢迎使用Pinia',
testPinia1: '欢迎使用Pinia1',
testPinia2: '欢迎使用Pinia2',
testArr: [1, 2, 3, 4]
}
},
getters: {},
actions: {
changeState(val: string) {
this.testPinia1 = '通过action修改成功';
}, changeState2(val: string) {
this.testPinia1 = val;
}
}
})
mainStory.changeState();
mainStory.changeState2("你好");
注意:
在使用action定义函数时,不能使用箭头函数
箭头函数绑定的外部this 而在函数体中无法使用当前的this
getters使用
getters是具有缓存功能的,在代码中连续实际只会执行一次
参数中的state是一个可选参数
getters: {
/*state:可选参数*/
addOne(state)
{
console.log("addOne被调用");
return state.count + 1;
}
}
<template>
<p>{{ mainStory.addOne }}</p>
<p>{{ mainStory.addOne }}</p>
<p>{{ mainStory.addOne }}</p>
</template>
<script setup lang="ts">
import {useMainStore} from '../story';
import {storeToRefs} from "pinia";
const mainStory = useMainStore()
const {testPinia1, testPinia2, testArr, count} = storeToRefs(mainStory)
</script>
源码地址:Vue3-Pinia