Pinia 状态管理
什么是 Pinia ?
Pinia最初是在 2019 年 11 月左右重新设计使用 Composition API的 Vue Store 外观的实验。从那时起,最初的原则仍然相同,但 Pinia 适用于 Vue 2 和 Vue 3 ,并且不需要你使用组合 API。除了安装和 SSR 之外,两者的 API 都是相同的,并且这些文档针对 Vue 3 ,并在必要时提供有关 Vue 2 的注释,以便 Vue 2 和 Vue 3 用户可以阅读!
为什么要使用 Pinia?
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。ç 这对于单页应用程序来说是正确的,但如果它是服务器端呈现的,则会将您的应用程序暴露给安全漏洞。 但即使在小型单页应用程序中,您也可以从使用 Pinia 中获得很多好处:
安装 Pinia
yarn add pinia# or with npmnpm install pinia
复制代码
Pinia 入门
store
可以通过 defineStore() 来定义 store 来存在管理状态,并且它需要一个唯一的名称,作为第一个参数传递:
import { defineStore } from 'pinia'
export const useStore = defineStore('main', { // other options...})
复制代码
使用 store
在组件内导入需要的 store,
注意⚠️:
store`是一个用 包裹的对象`reactive`,这意味着不需要`.value`在 getter 之后编写,但是像`props`in一样`setup
state
定义 state
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({ id: 'haijun', state: () => ({ // 定义状态属性 str: "前端自学社区" }),
})
复制代码
访问 state
通过store 实例来访问
<script setup lang="ts">import {useCounterStore} from '../stores/counter';
const store = useCounterStore()
onMounted(()=> { console.log(store.counter) //访问 state console.log(store.resultCode)})
</script>
复制代码
重制 state
可以通过调用 store 上的方法将状态重置为其初始值:$reset()
const store = useCounterStore()
store.$reset()
复制代码
改变 state
有两种方法
直接修改 state
const store = useCounterStore() store.code++
复制代码
通过 patch 来修改,一次可修改多个 state
const store = useCounterStore() store.$patch((state) => { state.code = 404 state.counter++ state.carList.push({id:3,name:'奥迪🇦🇹'}) })
复制代码
添加新的 state
有两种方法
通过 store 的 $state 来赋值一个对象,对象中可以添加多个state
store.$state = {title: '更换后的store' , author: '海军'}
复制代码
通过pinia实例来改变 state, 这在SSR 中使用。
订阅状态
观察状态和变化$subscribe()
<hr/>
Getter
Pinia 中的 getter 与 Vuex 中的getter 效果是一样的,接受一个 state 参数,用来访问store 的状态,具有缓存作用。
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({ id: 'counter', state: () => ({ counter: 0, code: 200, carList:[ { id:1, name: '特斯拉' }, { id:2, name: '奔驰' } ] }), getters: { doubleCount: (state) => state.counter * 2, resultCode: (state) => state.code + 4, otherGetter(){ return this.resultCode * 4 }, filterIdCarList: (state) => { return (id:number) => state.carList.filter(i => i.id == id) } },
})
复制代码
组件中访问 getter
直接通过store 实例上访问 getter:
<template> <p>Double count is {{ store.doubleCount }}</p></template>
<script setup lang="ts"> import {useCounterStore} from '../stores/counter'; const store = useCounterStore()</script>
复制代码
访问其它 Getter
可以在一个 getter 中访问其它的 getter 与 computer 类似。 它可以组合多个 getter, 可以通过 this 来访问多个 getter
getters: { doubleCount: (state) => state.counter * 2, resultCode: (state) => state.code + 4, // 组合 多个 getter 返回处理结果 otherGetter(){ return this.resultCode * 4 + this.doubleCount * 4 },},
复制代码
参数传递 Getter
getter 本身是用来计算的,本身不可能将参数传递给给它的。但可以通过返回一个函数来接受参数,进行状态处理。
getters: { //第一层传递参数 state, 以便在函数中处理 filterIdCarList: (state) => { //第二层: 返回一个函数,用来接收传递的参数,进行数据处理 return (id:number) => state.carList.filter(i => i.id == id) }}
复制代码
组件中使用
<h2>{{filterData(1)}}</h2><!-- [ { "id": 1, "name": "特斯拉" } ] 返回处理的结果-->
<script setup lang="ts">import {useCounterStore} from '../stores/counter';
const store = useCounterStore()const filterData = store.filterIdCarList</script>
复制代码
⚠️⚠️⚠️
通过返回函数后,它不具有缓冲的效果了,它只是调用了该函数。不过可以在 getter 内部做缓存结果。 【不常用】
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({ id: 'counter', state: () => ({ carList:[ { id:1, name: '特斯拉', sell: false }, { id:2, name: '奔驰', sell: true, price: 25 }, { id: 1, name: '奥迪Q5', sell: true, price: 67 } ] }), getters: { getSellCarList: (state) => { //用个变量存储起来 const filterIdCar = state.carList.filter(i => i.sell) return (price: number) => filterIdCar.filter(k => k.price == price) } }})
复制代码
访问其它 store 中的 getter
还可以访问其它 stroe 中的 getter,
导入其它storeimport { useOtherStore } from './other-store'
getters: { otherGetter(state) { const otherStore = useOtherStore //访问其它store 中的state return state.localData + otherStore.data }, },
复制代码
action
它 与 Vuex 中的 Action 是一样的效果,使用也一样。 它可以访问整个store 实例,它是异步的
export const useUsers = defineStore('users', { state: () => ({ userData: null, // ... }),
actions: { async registerUser(login, password) { try { this.userData = await api.post({ login, password }) showTooltip(`Welcome back ${this.userData.name}!`) } catch (error) { return error } }, },})
复制代码
在组件使用 action ,它和 getter 使用一样
<script setup lang="ts">import { useUsers } from '../stores/user';
const store = useUsers()const filterData = store.registerUser('admin','123456')</script>
复制代码
访问其它 store 实例
//user.js
import { defineStore } from 'pinia'
export const useMember = defineStore({ id: 'member', state: () => ({ memberList: [ { id: 111, name: '张飞' }, { id: 222, name: '小红' } ] }), getters: { addMember: (state) => { return (obj:any) => { state.memberList.push(obj) } } }, actions: {
}})
复制代码
import { defineStore } from 'pinia'import {useMember} from './user'// 导入axiosimport axios from 'axios'
export const useCounterStore = defineStore({ id: 'counter', state: () => ({
}), actions: {
async getMenuData(){ const useMembers = useMember() const resultData = await axios.get('http://localhost:3000/menu') //访问其它 store 的 getter state action useMembers.addMember({id:333,name: '老张'}) console.log(useMembers.memberList) } }})
复制代码
最后
欢迎一起交流学习,关注公众公众号:前端自学社区
评论