您现在的位置是:首页 >技术教程 >pinia的使用网站首页技术教程
pinia的使用
简介pinia的使用
介绍
- 一个拥有组合式 API 的 Vue 状态管理库
- 主要是面向 Vue 3 的用户,除了安装和 SSR 两章之外,其余章节中提到的 API 均支持 Vue 2 和 Vue
- Devtools 支持,追踪 actions、mutations 的时间线,在组件中展示它们所用到的 Store,让调试更容易的 Time travel
- 热更新。不必重载页面即可修改 Store,开发时可保持当前的 State
- 插件:可通过插件扩展 Pinia 功能
- 为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能。
- 支持服务端渲染
对比 Vuex
- 与 Vuex 相比,Pinia 提供了一个更简单的 API,mutation 已被弃用
- 提供了符合组合式 API 风格的 API,也可使用选项式API
- 搭配 TypeScript 一起使用时有非常可靠的类型推断支持
- Pinia 从设计上提供的是一个扁平的结构,不再有嵌套结构的模块,不再有可命名的modules。但可以通过导入和使用另一个 Store 来隐含地嵌套 stores 空间。
使用
yarn add pinia
npm install 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')
定义store文件
- 在store文件夹下新建user.js
- defineStore定义一个store
- 第一个参数是你的应用中 Store 的唯一 ID
- 第二个参数可接受两类值:Setup 函数或 Option 对象
- 仓库最好使用 store 的名字,同时以
use
开头且以Store
结尾。(比如useUserStore
,useCartStore
,useProductStore
)
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
})
Option Store 类似选项式API
export const useUserStore = defineStore('User', {
state: () => {
return {
count: 0, // 所有这些属性都将自动推断出它们的类型
}
},
getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlus() {
return this.doubleCount + 1
},
},
actions: {
increment() {
this.count++
},
},
})
Setup Store 类似组合式API 的 setup 函数
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
使用 Store
- store 是一个用 reactive 包装的对象,所以使用方式和reactive对象一样
<script setup>
import { useUserStore } from '@/store/user'
const userStore= useUserStore()
// ------------使用变量------
// userStore 是一个用 reactive 包装的对象
let count = userStore.count
// 所以reactive对象的属性不具有响应式,所以不能解构直接使用
// 若想解构,先将它每一个属性转化为响应式,类似roRefs()
import { storeToRefs } from 'pinia'
const { name, doubleCount } = storeToRefs(userStore)
// ----------使用方法---------
userStore.increment()
//或者解构:actions 的 increment 方法可以直接解构
const { increment } = userStore
increment()
</script>
修改state的三种方法
- 直接在页面组件中改变数据
- 使用$patch改变数据
- patch object:是通过我们熟悉的 $patch 的 对象方式 来变化
- patch function:也是通过 $patch,但是是通过 函数的方式 来变化
- direct:通过 action 变化
- 重置数据
<template>
<div>baseUrl:{{ baseUrl }}</div>
<div>ipList:{{ ipList }}</div>
<button @click="changeData">直接在页面组件中改变数据</button>
<button @click="changeDataByPatch">使用$patch改变数据</button>
<button @click="changeDataByAction">使用action改变数据</button>
<button @click="resetData">重置数据</button>
</template>
<script setup>
import useAppStore from "@/store/modules/app"
import { storeToRefs } from "pinia"
const store = useAppStore()
let { baseUrl, ipList } = storeToRefs(store)
/* 第一种修改方式:虽然可以直接修改,但是出于代码结构来说,
* 全局的状态管理还是不要直接在各个组件处随意修改状态,
* 应放于 action 中统一方法修改(piain没有mutation)
* 并不推荐!!!
* */
function changeData() {
store.baseUrl = 'https://www.taobao.com/'
store.ipList.push('192.168.10.111')
}
/*第二种修改方式:使用$patch改变数据, $patch 可以同时修改多个值
* $patch也有两种的调用方式
* 第一种写法的在修改数组时,假如我只想修改 ipList 的中第2项 , 也需要传入整个数组, 所以一般都推荐使用第二种传入一个函数的写法
*/
function changeDataByPatch() {
// 第一种 $patch方法
store.$patch({
baseUrl: 'https://www.jd.com/',
ipList: ['192.168.10.777', '192.168.10.222', '192.168.10.888']
})
// 第二种 $patch方法
store.$patch((state) => {
state.baseUrl = 'https://www.jd.com/'
state.ipList[1] = '192.168.10.222'
})
}
// 第三种修改方式:调用store中的action改变数据的方法changeState
function changeDataByAction() {
store.changeState('https://www.alibabagroup.com/cn/global/home') //可以直接给actions里面的方法传递参数
}
// 重置数据
function resetData() {
store.$reset()
}
</script>
订阅$subscribe:监听 state 里面的值是否发生了变化
cartStore.$subscribe((mutation, state) => {
console.log(mutation, state)
// mutation.type //发生改变的三种方式: 'direct' | 'patch object' | 'patch function'
// mutation.storeId // store名字
// mutation.payload // 传递给 cartStore.$patch() 的对象。只有 mutation.type === 'patch object'的情况下才可用
// 每当状态发生变化时,将整个 state 持久化到本地存储。
localStorage.setItem('cart', JSON.stringify(state))
})
//subscription 会被绑定到添加它们的组件上 ,当该组件被卸载时,它们将被自动删除。如果想保留,设置 { detached: true } ,以将 state subscription 从当前组件中分离
cartStore.$subscribe(callback, { detached: true })
当前 getter 访问其他 store 的 getter
import { useOtherStore } from './other-store'
export const useStore = defineStore('main', {
getters: {
otherGetter(state) {
const otherStore = useOtherStore()
return state.localData + otherStore.data
},
},
})
订阅 action
const unsubscribe = someStore.$onAction(
({
name, // action 名称
store, // store 实例,类似 `someStore`
args, // 传递给 action 的参数数组
after, // 在 action 返回或解决后的钩子
onError, // action 抛出或拒绝的钩子
}) => {
// 为这个特定的 action 调用提供一个共享变量
const startTime = Date.now()
// 这将在执行 "store "的 action 之前触发。
console.log(`Start "${name}" with params [${args.join(', ')}].`)
// 这将在 action 成功并完全运行后触发。
// 它等待着任何返回的 promise
after((result) => {
console.log(
`Finished "${name}" after ${
Date.now() - startTime
}ms.
Result: ${result}.`
)
})
// 如果 action 抛出或返回一个拒绝的 promise,这将触发
onError((error) => {
console.warn(
`Failed "${name}" after ${Date.now() - startTime}ms.
Error: ${error}.`
)
})
}
)
// 手动删除监听器
unsubscribe()
// 此订阅器即便在组件卸载之后仍会被保留
someStore.$onAction(callback, true)
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。