Pinia基础及使用方法

一、什么是Pinia?

简单来说,Pinia是vueX的新版本,我们都知道Vuex在Vue2中主要充当状态管理的角色,所谓状态管理,就是一个存储数据的地方,存放在Vuex中的数据在各个组件中都能访问到,它是Vue生态中重要的组成部分。

Vue3中,可以使用传统的Vuex来实现状态管理,也可以使用最新的pinia来实现状态管理。Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。Pinia和Vuex的作用是一样的,它也充当的是一个存储数据的作用,存储在pinia的数据也允许我们在各个组件中使用。

总的来说,Pinia就是Vuex的升级版,官网也说过,为了尊重原作者,所以取名Pinia,而没有取名Vuex,所以大家可以直接将pinia比作为Vue3的Vuex。

二、为什么要使用Pinia?

  • 完整的 ts 的支持;
  • 足够轻量,压缩后的体积只有1kb左右;
  • 去除 mutations,只有 state,getters,actions;
  • actions 支持同步和异步;
  • 代码扁平化没有模块嵌套,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的;
  • 无需手动添加 store,store 一旦创建便会自动添加;
  • 支持Vue3 和 Vue2。

三、Pinia基础使用方法

1. 安装

npm install pinia

2. 引入

Vue2版本

import { PiniaVuePlugin } from 'pinia'
 
Vue.use(PiniaVuePlugin)
 
new Vue({
  el: '#app',
  // other options...
  // ...
  // note the same `pinia` instance can be used across multiple Vue apps on
  // the same page
  pinia,
})

Vue3版本

import { createApp } from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
 
const store = createPinia()  // 导入以后就是插件,用use注册
let app = createApp(App)
 
app.use(store)
 
app.mount('#app')

3. 初始化仓库store

1、新建一个文件夹Store,新建文件index.js/ts

2、定义仓库Store

使用pinia提供的defineStore()方法来创建一个store,该store用来存放我们需要全局使用的数据。

import { defineStore } from 'pinia'
 
// 第一个参数是应用程序中 store 的唯一 id
// 第二个参数是对象,存放state、getters、actions
export const useUsersStore = defineStore('users', {
  // 其它配置项
})

3、定义配置项

import { defineStore } from 'pinia'
 
export const useTestStore = defineStore('user', {
     state:()=>{
         return {
             current:1
         }
     },
     //类似于computed 可以帮我们去修饰我们的值
     getters:{
 
     },
     //可以操作异步 和 同步提交state
     actions:{
 
     }
})

4. state

修改方法有3种

1、直接修改

<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {
   
   {Test.current}}
          </div>
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
    Test.current++
}
 
</script>
 
<style>
 
</style>

2、用特有方法$patch,可批量修改多个数据

<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {
   
   {Test.current}}
          </div>
          <div>
            {
   
   {Test.age}}
          </div>
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
    Test.$patch({
       current:200,
       age:300
    })
}
 
</script>
 
<style>
 
</style>

3、用$patch的函数形式更改数据,需要传递参数state

<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {
   
   {Test.current}}
          </div>
          <div>
            {
   
   {Test.age}}
          </div>
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
    Test.$patch((state)=>{
       state.current++;
       state.age = 40
    })
}
 
</script>
 
<style>
 
</style>

4、用原始对象$state修改,缺点是需要修改所有的值,也就是用一个新的数据对象覆盖原有数据对象

<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {
   
   {Test.current}}
          </div>
          <div>
            {
   
   {Test.age}}
          </div>
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
    Test.$state = {
       current:10,
       age:30
    }    
}
 
</script>
 
<style>
 
</style>

5、actions修改,不要写箭头函数否则this不能用了

import { defineStore } from 'pinia'
import { Names } from './store-naspace'
export const useTestStore = defineStore(Names.TEST, {
     state:()=>{
         return {
            current:1,
            age:30
         }
     },
 
     actions:{
         setCurrent () {
             this.current++
         }
     }
})
 
<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {
   
   {Test.current}}
          </div>
          <div>
            {
   
   {Test.age}}
          </div>
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
     Test.setCurrent()
}
 
</script>
 
<style>
 
</style>

5. actions

1、同步方法,直接调用即可

import { defineStore } from 'pinia'
import { Names } from './store-naspace'
export const useTestStore = defineStore(Names.TEST, {
    state: () => ({
        counter: 0,
    }),
    actions: {
        increment() {
            this.counter++
        },
        randomizeCounter() {
            this.counter = Math.round(100 * Math.random())
        },
    },
})
 
-------------------------------------------------------
 
<template>
     <div>
         <button @click="Add">+</button>
          <div>
             {
   
   {Test.counter}}
          </div>    
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
     Test.randomizeCounter()
}
 
</script>
 
<style>
 
</style>

2、异步方法,async await

import { defineStore } from 'pinia'
import { Names } from './store-naspace'
 
type Result = {
    name: string
    isChu: boolean
}
 
const Login = (): Promise<Result> => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({
                name: '小满',
                isChu: true
            })
        }, 3000)
    })
}
 
export const useTestStore = defineStore(Names.TEST, {
    state: () => ({
        user: <Result>{},
        name: "123"
    }),
    actions: {
        async getLoginInfo() {
            const result = await Login()
            this.user = result;
        }
    },
})
 
---------------------------------------------------------------
 
<template>
     <div>
         <button @click="Add">test</button>
          <div>
             {
   
   {Test.user}}
          </div>    
     </div>
</template>
 
<script setup lang='ts'>
import {useTestStore} from './store'
const Test = useTestStore()
const Add = () => {
     Test.getLoginInfo()
}
 
</script>
 
<style>
 
</style>

3、可以调用其他方法

    state: () => ({
        user: <Result>{},
        name: "default"
    }),
    actions: {
        async getLoginInfo() {
            const result = await Login()
            this.user = result;
            this.setName(result.name)
        },
        setName (name:string) {
            this.name = name;
        }
    },

6. getters

1、写法一:箭头函数,参数为state

    getters:{
       newPrice:(state)=>  `$${state.user.price}`
    },

2、写法二:普通函数

    getters:{
       newCurrent ():number {
           return ++this.current
       }
    },

3、相互调用

    getters:{
       newCurrent ():number | string {
           return ++this.current + this.newName
       },
       newName ():string {
           return `$-${this.name}`
       }
    },

7. 解构

在Pinia不允许直接解构,会失去响应性。像下面这样解构,改变数据后数据是发生改变了,但是不会响应到页面上。

const Test = useTestStore()
 
const { current, name } = Test
 
console.log(current, name);

解决方案:storeToRefs

import { storeToRefs } from 'pinia'
 
const Test = useTestStore()
 
const { current, name } = storeToRefs(Test)

8. 实例API

1、$state:修改state的值

在state里已介绍

2、$reset:重置store为初始状态

3、$subscribe:类似于Vuex 的abscribe  只要有state 的变化就会走这个函数

Test.$subscribe((args,state)=>{
   console.log(args,state);
   
})

如果你的组件卸载之后还想继续调用请设置第二个参数:

Test.$subscribe((args,state)=>{
   console.log(args,state);
   
},{
  detached:true
})

4、$onAction:只要有actions被调用就会走这个函数

Test.$onAction((args)=>{
   console.log(args);
   
})

9. 持久化插件

Pinia 和 Vuex 都有一个通病:页面刷新状态会丢失,写一个Pinia 插件缓存他的值

const __piniaKey = '__PINIAKEY__'
//定义兜底变量 
 
type Options = {
   key?:string
}
//定义入参类型
 
//将数据存在本地
const setStorage = (key: string, value: any): void => {
    localStorage.setItem(key, JSON.stringify(value))
}
 
//存缓存中读取
const getStorage = (key: string) => {
    return (localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string) : {})
}
 
//利用函数柯丽华接受用户入参
const piniaPlugin = (options: Options) => {
    //将函数返回给pinia  让pinia  调用 注入 context
    return (context: PiniaPluginContext) => {
        const { store } = context;
        const data = getStorage(`${options?.key ?? __piniaKey}-${store.$id}`)
        store.$subscribe(() => {
            setStorage(`${options?.key ?? __piniaKey}-${store.$id}`, 
            toRaw(store.$state));
            //返回值覆盖pinia 原始值
            return {
                 ...data
            }
        }
}
 
//初始化pinia
const pinia = createPinia()
 
//注册pinia 插件
pinia.use(piniaPlugin({
    key: "pinia"
 
}))

猜你喜欢

转载自blog.csdn.net/weixin_42775304/article/details/132108441