Vue3学习 pinia
- pinia
- 一个简单效果
- 搭建 pinia 环境
- 存储+读取数据
- 示例
- 修改数据 (三种方式)
- storeToRefs
- getters
- $subscribe
- store组合式写法
pinia
在vue2中使用vuex,在vue3中使用pinia。
集中式状态管理,(状态=数据)。多个组件共享数据的时候使用。
一个简单效果
- Count.vue
注意事项①select中的数字限制 v-model.number ② ref响应式数据 要加value
<template><div class="count"><h1>当前求和为:{{ sum }}</h1><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="add">加</button><button @click="minus">减</button></div>
</template><script setup lang="ts" name="Count">import {ref} from 'vue'let sum = ref(0)let n = ref(1) // 用户选择的数字// 方法function add(){sum.value += n.value}function minus(){sum.value -= n.value}
</script><style>
.count {background-color: skyblue;padding: 10px;padding: 10px;border-radius: 10px;
}
select,button {margin-left: 10px;
}
</style>
- LoveTalk.vue
注意事项 ① axios的 async await写法,② reactive监测数组的变化(unshift),③ 连续解构赋值+重命名
<template><div class="talk"><button @click="getLoveTalk">获取一句土味情话</button><ul><li v-for="talk in talkList" :key="talk.id">{{talk.title}}</li></ul></div>
</template><script setup lang="ts" name="LoveTalk">import {reactive} from 'vue'import axios from "axios";import {nanoid} from 'nanoid'// 数据let talkList = reactive([{id:'ftrfasdf01',title:'今天你有点怪,哪里怪?怪好看的!'},{id:'ftrfasdf02',title:'草莓、蓝莓、蔓越莓,今天想我了没?'},{id:'ftrfasdf03',title:'心里给你留了一块地,我的死心塌地'}])// 方法async function getLoveTalk(){// 发请求,下面这行的写法是:连续解构赋值+重命名let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')// 把请求回来的字符串,包装成一个对象let obj = {id:nanoid(),title}// 放到数组中talkList.unshift(obj)}
</script><style scoped>.talk {background-color: orange;padding: 10px;border-radius: 10px;}
</style>
- App.vue
<template><Count></Count><hr><LoveTalk></LoveTalk>
</template><script lang="ts" setup name="App">import Count from './components/Count.vue';import LoveTalk from './components/LoveTalk.vue';</script>
搭建 pinia 环境
第一步:npm install pinia
第二步:操作src/main.ts
import { createApp } from 'vue'
import App from './App.vue'/* 引入createPinia,用于创建pinia */
import { createPinia } from 'pinia'/* 创建pinia */
const pinia = createPinia()
const app = createApp(App)/* 使用插件 */
app.use(pinia)
app.mount('#app')
此时开发者工具中已经有了pinia
选项
存储+读取数据
-
Store
是一个保存:状态、业务逻辑 的实体,每个组件都可以读取、写入它。(/src/store/xxx.ts) -
它有三个概念:
state
、getter
、action
,相当于组件中的:data
、computed
和methods
。 -
具体编码:
src/store/count.ts
// 引入defineStore用于创建store import {defineStore} from 'pinia'// 定义并暴露一个store export const useCountStore = defineStore('count',{// 动作actions:{},// 状态state(){return {sum:6}},// 计算getters:{} })
-
具体编码:
src/store/talk.ts
// 引入defineStore用于创建store import {defineStore} from 'pinia'// 定义并暴露一个store export const useTalkStore = defineStore('talk',{// 动作actions:{},// 状态state(){return {talkList:[{id:'yuysada01',content:'你今天有点怪,哪里怪?怪好看的!'},{id:'yuysada02',content:'草莓、蓝莓、蔓越莓,你想我了没?'},{id:'yuysada03',content:'心里给你留了一块地,我的死心塌地'}]}},// 计算getters:{} })
-
组件中使用
state
中的数据<template><h2>当前求和为:{{ sumStore.sum }}</h2> </template><script setup lang="ts" name="Count">// 引入对应的useXxxxxStore import {useSumStore} from '@/store/sum'// 调用useXxxxxStore得到对应的storeconst sumStore = useSumStore() </script>
<template><ul><li v-for="talk in talkStore.talkList" :key="talk.id">{{ talk.content }}</li></ul> </template><script setup lang="ts" name="Count">import axios from 'axios'import {useTalkStore} from '@/store/talk'const talkStore = useTalkStore() </script>
示例
我想让 count.vue中的sum变量、Lovetalk.vue中的talkList变成共有的
① npm i pinia
② 创建store文件夹,store可以理解为 使用pinia的实体。里面对应组件创建ts文件
count.ts
import {defineStore} from 'pinia'// useCountStore和hooks命名方法一致
export const useCountStore = defineStore('count', {// 真正存储数据的地方state(){ 状态(数据)return {sum :6}}
})
loveTalk.ts
import {defineStore} from 'pinia'// useCountStore和hooks命名方法一致
export const useTalkStore = defineStore('talk', {// 真正存储数据的地方state(){ 状态(数据)return {talkList: [{id:'ftrfasdf01',title:'今天你有点怪,哪里怪?怪好看的!'},{id:'ftrfasdf02',title:'草莓、蓝莓、蔓越莓,今天想我了没?'},{id:'ftrfasdf03',title:'心里给你留了一块地,我的死心塌地'}]}}
})
③ 在组件中使用 store里的数据
count.vue
<template><div class="count"><h1>当前求和为:{{ countStore.sum }}</h1></div>
</template><script setup lang="ts" name="Count">// let sum = ref(0)import { useCountStore } from '@/store/count';const countStore = useCountStore()//console.log(countStore);// 以下两种方式都可以拿到state中的 数据//console.log(countStore.sum);//console.log(countStore.$state.sum);
</script>
拿到 store 中的数据:
import { useCountStore } from '@/store/count';const countStore = useCountStore()
打印countStore:
修改数据 (三种方式)
import { useCountStore } from '@/store/count';
const countStore = useCountStore()
-
第一种修改方式,直接修改
countStore.sum = 666
-
第二种修改方式:批量修改
countStore.$patch({sum:999,school:'atguigu' })
-
第三种修改方式:借助
action
修改(action
中可以编写一些业务逻辑)底层维护了一个this。
import { defineStore } from 'pinia'export const useCountStore = defineStore('count', {/*************/actions: {//加increment(value:number) {if (this.sum < 10) {//操作countStore中的sumthis.sum += value}},//减decrement(value:number){if(this.sum > 1){this.sum -= value}}},/*************/ })
组件中调用
action
即可// 使用countStore const countStore = useCountStore()// 调用对应action countStore.incrementOdd(n.value)
storeToRefs
借助storeToRefs
将store
中的数据转为ref
对象,方便在模板中使用。
注意:pinia
提供的storeToRefs
只会将数据做转换,不会对方法进行包裹。而Vue
的toRefs
会转换store
中数据。
<template><div class="count"><h2>当前求和为:{{sum}}</h2></div>
</template><script setup lang="ts" name="Count">import { useCountStore } from '@/store/count'/* 引入storeToRefs */import { storeToRefs } from 'pinia'/* 得到countStore */const countStore = useCountStore()/* 使用storeToRefs转换countStore,随后解构 */const {sum} = storeToRefs(countStore)
</script>
getters
-
概念:当
state
中的数据,需要经过处理后再使用时,可以使用getters
配置。类似computedgetters 中维护的this也是store
-
追加
getters
配置。// 引入defineStore用于创建store import {defineStore} from 'pinia'// 定义并暴露一个store export const useCountStore = defineStore('count',{// 动作actions:{/************/},// 状态state(){return {sum:1,school:'atguigu'}},// 计算getters:{bigSum: state => state.sum *10,upperSchool():string{return this.school.toUpperCase()}} })
-
组件中读取数据:
const {increment,decrement} = countStore let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)
$subscribe
通过 store 的 $subscribe()
方法侦听 state
及其变化
- LoveTalk.vue
import { useTalkStore } from '@/store/count';
const talkList = useTalkStore()talkStore.$subscribe((mutate,state)=>{// console.log('talkStore发生变化');console.log('LoveTalk',mutate,state)localStorage.setItem('talk',JSON.stringify(talkList.value))
})
- loveTalk.ts
export const useTalkStore = defineStore('talk', {state(){ return {// 断言+空数组talkList: JSON.parse(localStorage.getItem('talk') as string)||[]}}...
})
store组合式写法
- 之前是选项式
import {defineStore} from 'pinia'
import axios from "axios";
import {nanoid} from 'nanoid'// defineStore('名字',{配置对象})
export const useTalkStore = defineStore('talk', {state(){ return {talkList: JSON.parse(localStorage.getItem('talk') as string)||[]}},actions: {async getATalk(){// 发请求,下面这行的写法是:连续解构赋值+重命名let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')// 把请求回来的字符串,包装成一个对象let obj = {id:nanoid(),title}// 放到数组中this.talkList.unshift(obj)}},getters:{}
})
-
组合式写法(注意defineStore的第二项变为函数,需要返回值)
① state数据直接用 reactive/ref
② actions里面的函数配置,写为function函数
③ 没有this了
import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'export const useTalkStore = defineStore('talk',()=>{// talkList就是stateconst talkList = reactive(JSON.parse(localStorage.getItem('talkList') as string) || [])// getATalk函数相当于actionasync function getATalk(){// 发请求,下面这行的写法是:连续解构赋值+重命名let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')// 把请求回来的字符串,包装成一个对象let obj = {id:nanoid(),title}// 放到数组中talkList.unshift(obj)}return {talkList,getATalk}
})
- count.ts
import {ref} from 'vue'
export const useCountStore = defineStore('count',()=>{let sum = ref(6)function increment(value:number) {if (sum.value < 10) {//操作countStore中的sumsum.value += value}}//减function decrement(value:number){if(sum.value > 1){sum.value -= value}}return {sum,increment,decrement}
})