拥抱pinia,快速上手,详解指南

·  阅读 5266
拥抱pinia,快速上手,详解指南

新的一年了,还在忍受Vuex4糟糕的类型体验?🙅‍,我们要把 Vuex 换成 Pinia 了💪;Pinia ,Vue.js 官方开发,下一代的 Vuex,简化的概念,更好的 TypeScript 支持。快来一起体验吧~~

简介

Pinia 是一个 Vue 的存储库, Pinia最初是一个实验,它的作者是Vue.js核心团队的成员,本来是为了测试Vuex5提案而出现的,在2019年11月左右重新设计的Vue状态管理以适用于 Composition API,它不但支持Vue3也支持Vue2的options API,也是下一代的轻量级状态管理库。

官网:pinia.vuejs.org/

我们知道在不同版本的Vue中,所需要使用的状态管理库Vuex版本也是不一样的,不然就会有错误发生。

vue2.x 我们使用--》 vuex 3.x版本

vue3.x 我们使用--》vuex 4.x版本

然鹅鹅🤷‍♀️,我们的Pinia就不会有这个限制啦~~ 它不但支持Vue3也支持Vue2,且不一定要与 Composition API 一起使用,API 的使用方式在两者中也是保持一致的。★,°:.☆( ̄▽ ̄)/$: .°★ 。🌹🌹🌹

核心概念

  1. State: 用于存放数据,有点儿类似 data 的概念;
  2. Getters: 用于获取数据,有点儿类似 computed 的概念;
  3. Actions: 用于修改数据,有点儿类似 methods 的概念;
  4. Plugins: Pinia 插件。

❓为啥说Pinia是下一代的轻量级状态管理库

我们先来看看官方对官方对 Vuex5 的 Rfcs 提案如下图:github.com/vuejs/rfcs/…

image.png

而这些与不pinia的功能类似么?而且在这个提案下方的评论中 也可以看到

image.png

为啥用Pinia

在前边也介绍了Pinia是vue的官方核心开发成员开发的,天然对vue是支持的,设计也非常接近vuex5的提案,甚至vuex5的部分灵感都是来自于pinia,那究竟它到底有哪些优势呢?类比vuex 4.x好在哪呢?

那么接下来我们来看看vuex 4.x的缺点:

  • 1、改变一个state的值,如果是同步更新需要mutations,异步的时候需要在actions
  • 2、给Vuex的state添加typescript,需要自定义复杂的类型来支持ts
  • 3、把vue想中的state分成多个部分,就需要用到 module
  • 4、从vue3开始。getters的结果不会像计算属性那样缓存了
  • 5、vuex4.X有一些与类型安全相关的问题

没有命名空间的模块,或者说所有的store都是命名空间

优势

  • 完整的 TypeScript 支持;天生具备完美的类型推断
  • 支持两种语法创建 Store:Options ApiComposition Api
  • 类比vuex 4.xPinia删除 mutations;统一在 actions 中操作 state,通过this.xx 访问相应状态虽然可以直接操作 Store,但还是推荐在 actions 中操作,保证状态不被意外改变
  • Store中的Actions 配置项可以执行同步或异步方法,且 action 被调用的是为常规的函数调用,而不是使用 dispatch 方法或 MapAction 辅助函数
  • 可以构建多个store,打包管理会自动拆分
  • 模块化的设计,便于拆分状态,能很好支持代码分割;
  • 没有嵌套的模块,只有 Store 的概念,可以声明多个Store,Pinia在设计上提供了一个扁平的结构,仍然能够在存储空间之间进行交叉组合,
  • 无需动态添加stores,默认都是动态的;
  • 没有命名空间的模块 namespaced模块,或者说所有的store都是命名空间
  • Pinia 可以自由扩展 插件功能官方文档 Plugins
  • 极轻, 仅有 1 KB
  • 支持Vue DevTools, SSR和Webpack 代码拆分
  • 无论是在 Vue2 中,还是在 Vue3 中均可以使用 Pinia,且不一定要与 Composition API 一起使用,API 的使用方式在两者中也是保持一致的。

Pinia与Vuex代码分割机制

image.png

Vuex的代码分割: 打包时,vuex会把3个store合并打包,当首页用到Vuex时,这个包会引入到首页一起打包,最后输出1个js chunk。这样的问题是,其实首页只需要其中1个store,但其他2个无关的store也被打包进来,造成资源浪费。

image.png

Pinia的代码分割: 打包时,Pinia会检查引用依赖,当首页用到main store,打包只会把用到的store和页面合并输出1个js chunk,其他2个store不耦合在其中。Pinia能做到这点,是因为它的设计就是store分离的,解决了项目的耦合问题。


使用pinia会让你真香的!!!!

image.png

快速上手

安装

我们可以在已有的vue项目中直接安装pinia使用状态管理,与已经安装的vuex不会有依赖冲突,在这我们就新建一个项目来一步一步的看看吧,这边举例子的是vue3的项目,这样可以更好的结合ts来看看吧~

使用vite创建一个vue-ts的项目,(因为pinia是专门用于vue的所以要选用vue,最后用于ts因为更香,只用js不能更加体会pinia的好用呀)

关于vite创建前端框架项目的详解可以查看之前的文章:前端框架:vite2+vue3+typescript+axios+vant移动端 框架实战项目详解(一)

第一步:使用vite创建一个vue-ts的项目

npm init @vitejs/app <project-name> --template
复制代码

第二步:安装状态管理依赖pinia

yarn add pinia@next 
# or with npm 
npm install pinia@next
// 该版本与Vue 3兼容,如果你正在寻找与Vue 2.x兼容的版本,请查看v1分支。 
复制代码

初始化配置

在入口文件main.ts中 创建一个 pinia(根存储)并将其传递给应用程序:

import { createApp } from 'vue'
import App from './App.vue'
​
import { createPinia } from 'pinia'
​
// 创建Pinia实例
const pinia = createPinia()
// 实例化 Vue
createApp(App)
.use(pinia) // 挂载到Vue根实例上
.mount('#app') // 挂载在真实 DOM
复制代码

在上面的代码中,你将Pinia添加到Vue.js项目中,我们可以看到里边可以结构一个方法 createPinia在挂载到Vue根实例上, 这样你就可以在你的代码中使用Pinia的全局对象。

使用

按照以往惯例我们会在项目src下,创建一个store来专门存放状态管理,,然后在用到该数据的地方进行导入,我们使用pinia也是如此。

基本使用及解析

步骤:

  • 1.定义容器
  • 2.使用容器中的state
  • 3.修改state
  • 4.容器中的action的state

1.定义容器

在文件中声明store

创建src/store/index.ts 用来存放状态管理

第一种模式Store

类似 vuex 的方式来构建 state

import { defineStore } from "pinia";
​
// 参数1:容器的ID,必须唯一 将来pinia会把所有的容易挂载到根容器
// 参数2:选项对象
// 返回值是一个函数 调用得到  对外部暴露一个 use 方法,该方法会导出我们定义的 state
export const useMainStore = defineStore("main", {
  /**
   * 类似于组件的data 用来存储全局状态
   */
  state: () => {
    return {
      countPinia: 100
    };
  },
  
  // 也可以这样定义
  // state: () => ({ countPinia: 100 }),
   getters: {
    double () {
     // getter 中的 this 指向👉 state
        return this.countPinia * 2
     },
   // 如果使用箭头函数会导致 this 指向有问题
   // 可以在函数的第一个参数中拿到 state
    double2: (state) => {
     return state.count * 2
   }
  },
  // actions 用来修改 state
  actions: {
    increment() {
      // action 中的 this 指向👉 state
      this.countPinia++
    },
​
});
​
​
复制代码

也可以写成一下方式

export const useMainStore = defineStore({
    id: 'main',
    state: () => {
        return {
            countPinia: 100
        }
    },
  ...
})
复制代码

第二种方式模式

使用 function 的形式来创建 store,有点类似于 Vue3 中的 setup

import { ref, computed } from "vue"
import { defineStore } from "pinia"
 
// 对外部暴露一个 use 方法,该方法会导出我们定义的 state
const useMainStore = defineStore('main', function () {
  const countPinia = ref(0)
  const double = computed(() => countPinia.value * 2)
  function increment() {
    countPinia.value++
  }
  return {
   countPinia, double, increment
  }
})
 
export default useMainStore
复制代码
👨‍🎓解析代码:

Pinia通过defineStore函数来创建一个store,它接收一个id用来标识store,以及store选项

为了创建一个store,你用一个包含创建一个基本store所需的states、actions和getters的对象来调用 defineStore 方法。

这个方法返回一个函数, 对外部暴露这个方法,该方法会导出我们定义的 state;

defineStore 方法 有两个参数

  • 参数1:容器的ID,必须唯一 将来pinia会把所有的容易挂载到根容器
  • 参数2:选项对象

2.使用容器中的state

上边pinia优势中的时候说过,Pinia 提供了两种方式来使用 store,Options ApiComposition Api 中都完美支持

Vue2 与 Vue3 最大的区别: Vue2 使用Options API而 Vue3 使用的Composition API

使用options API模式定义,这种方式和vue2的组件模型形式类似,也是对vue2技术栈开发者较为友好的编程模式。

还有就是 Composition Api,我们这边使用setup模式定义,符合Vue3 setup的编程模式,让结构更加扁平化,个人推荐推荐使用这种方式。

Options Api方式使用

Options Api 中,可直接使用官方提供的 mapActionsmapState 方法,导出 store 中的 state、getter、action,其用法与 Vuex 基本一致,很容易上手。

import { mapActions, mapState } from 'pinia'
import { useMainStore } from '@/store'
 
export default {
  name: 'HelloWorld',
  computed: {
    ...mapState(useMainStore, ['countPinia', 'double'])
  },
  methods: {
    ...mapActions(useMainStore, ['increment'])
  }
​
复制代码

Composition Api模式使用

<script setup lang="ts">
import { useMainStore } from './store'
const useMain = useMainStore()
const { countPinia} = useMain
const clickEdit = ()=>{
   useMain.increment()
}
</script>
​
<template>
  <h2>{{ useMain }}</h2>
  <h2>{{ useMain.countPinia }}</h2>
  <p>{{useMain.double}}</p>
  <button @click="clickEdit">修改数据</button>
</template>
复制代码

也可以结合 computed 获取。

const countPiniaComputed = computed(() => useMainStore.countPinia)
复制代码
👨‍🎓解析代码:
  • 1、const { countPinia} = useMain 这种方式的解构,是有一些问题的,数据不能够实现响应式,那需要怎么做呢?这时候可以用 pinia 的 storeToRefs。如下
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useMainStore } from './store'
const useMain = useMainStore()
const { countPinia } = storeToRefs(useMain)
</script>
​
<template>
  <h2>{{ useMain }}</h2>
  <h2>{{ useMain.countPinia }}</h2>
  <p>{{countPinia}}</p>
</template>
复制代码

useMain 是一个用reactive包装的对象,这意味着没有必要在getters之后写入.value,但是如果想结构这种方式就是破坏了响应性类似从props中一样。所以我们要使用pinia中的storeToRefs来包裹,就可以啦~~

因为pinia其实就是把state数据都做了 reactive 处理了~~

ps:这个时候其实我们可以体会到因为pinia的支持ts,所以会有很好的提示,可以快速的开发,相当优秀;如果我们想要这些提示,那么需要改写vuex 4.x 方法,就需要手动声明类型

  • 2、Pinia在setup模式下的调用机制是先install再调用
  • 3、可以定义任意多的stores,在真正的 useMainStore()执行之前,store并不会被创建,一旦存储被实例化,您就可以直接在存储上访在“state”、“getters”和“actions”中定义的任何属性。
  • 4、如果我们使用 Vue 2的项目中使用pinia,在 state 中创建的数据遵循与 data 在 Vue 实例中 相同的规则,即 状态对象必须是普通的,并且您需要在向其添加新属性Vue.set()时调用

3.修改state

Composition Api 中,不管是 state 还是 getter 都需要通过 computed 方法来监听变化,这和 Options Api 中,需要放到 computed 对象中的道理一样。

Options Api 中拿到的 state 值是可以直接进行修改操作的,当然还是建议写一个 action 来操作 state 值,方便后期维护。

方式一:最简单的方式:

Options Api 中拿到的 state 值是可以直接进行修改操作的,

// 组件中
useMain.countPinia++
复制代码

方式二: $path 批量更新1

如果需要修改多个数据,建议使用 path批量更新,相比方式一:这种写法不是写法上的简单优化,path 批量更新,相比方式一:这种写法不是写法上的简单优化,path是有性能的优化

// 组件中
useMain.$patch({
  countPinia: useMain.countPinia+1
})
复制代码

方式三:$patch 使用一个函数

也是批量更新 (好处,相比较方法二,在处理一些复杂的数据时,如数组、对象等更简单)

// 组件中
useMain.$patch(state=>{
    state.countPinia++
})
复制代码

方式四:封装到action

逻辑比较多的时候,可以封装到action(最常用的) actions 去修改 state,action 里可以直接通过 this 访问。

// 组件中
useMain.changeState()
复制代码

src/store/index.ts 中在action添加方法

//src/store/index.ts
​
import { defineStore } from "pinia";
​
// 参数1:容器的ID,必须唯一 将来pinia会把所有的容易挂载到根容器
// 参数2:选项对象
// 返回值是一个函数 调用得到  对外部暴露一个 use 方法,该方法会导出我们定义的 state
export const useMainStore = defineStore("main", {
  /**
   * 类似于组件的data 用来存储全局状态
   */
  state: () => {
    return {
      countPinia: 100
    };
  },
  /**
   * 类似组件的computed 用于封装计算属性,有缓存的功能
   */
  getters: {
  },
  /**
   * 类似于组件的methods 封装有误逻辑 修改 state
   */
  actions: {
  changeState() {
      // this.countPinia++
​
      this.$patch(state => {
        state.countPinia++;
      });
    }
  }
});
复制代码
👨‍🎓解析代码注意:

不能使用箭头函数定义action 因为使用箭头函数 函数内部的this指向就是外部

良好的编程习惯:state的改变交给action去处理

核心概念详解

State

在 Pinia 中,State状态被定义为返回初始状态的函数。类似于组件的data 用来存储全局状态

options api中定义的时候

  • 1.必须是函数:这样是为了在服务器渲染的时候避免交叉请求导致的数据状态污染

  • 2.推荐用箭头函数,这是为了更好的 TS 类型推导

import { defineStore } from 'pinia'
​
const useMainStore = defineStore('main', {
  // 推荐用于全类型推理的箭头函数
  state: () => {
    return {
      // 所有这些属性都将自动推断出它们的类型
      counter: 0,
      name: 'lee'
    }
  },
})
复制代码

技巧:

如果您使用 Vue 2,您在 state 中创建的数据遵循与 data 在 Vue 实例中 相同的规则,即 状态对象必须是普通的,并且您需要在向其添加新属性Vue.set()时调用

另请参阅: Vue#data

Composition Api模式定义

使用setup模式定义

import { ref } from 'vue';
import { defineStore } from 'pinia';
​
// 使用setup模式定义
export const useCounterStoreForSetup = defineStore('counter', () => {
  const count = ref<number>(1);
​
  return { count};
});
​
复制代码

1、访问state

引入创建的store容器,调用后通过实例访问状态来直接读取和写入状态

<script setup lang="ts">
import { useMainStore,useCounterStoreForSetup } from './store'
const useMain = useMainStore()
const useCounterForSetup = useCounterStoreForSetup()
</script>
​
<template>
  <h2>{{ useMain.countPinia++ }}</h2>
  <hr>
  
  <p>{{useCounterForSetup.count++}}</p>
</template>
复制代码

2、重置state

可以通过调用store 上的方法将状态重置为其初始值$reset()

<script setup lang="ts">
import { useMainStore,useCounterStoreForSetup } from './store'
const useMain = useMainStore()
const useCounterForSetup = useCounterStoreForSetup()
useMain.$reset()
</script>
复制代码

3、修改

具体可看上边的 使用中的修改state

  • 直接修改
  • 通过调用$patch方法允许您对部分state对象批量更改
  • 或者在action方法中修改
  • 可以通过将 store$state属性设置为新对象来替换 store 的整个状态;useMain.$state = { countPinia: 666 }
  • 可以通过更改替换您的应用程序的整体状态state中的pinia实例. pinia.state.value = {}

4、订阅状态

可以通过$subscribe()store的方法观察状态及其变化,类似于 Vuex 的 subscribe 方法

$subscribe() 与常规相比使用的优点watch()订阅只会在 patch 后触发一次(例如,使用上面的函数版本时)。

useMain.$subscribe((mutation, state)=>{
  localStorage.setItem('useMain-state', JSON.stringify(state))
})
复制代码

👨‍🎓解析代码注意:

当useMain中的state改变时,本地缓存中就会被存储这些useMain的整个state

默认情况下,状态订阅绑定到添加它们的组件(如果存储在组件的内部setup())。意思是,当组件被卸载时,它们将被自动删除。如果你想保持他们后成分是卸载,通过{ detached: true }作为第二个参数,以分离状态订阅从当前组件:

useMain.$subscribe((mutation, state)=>{
  localStorage.setItem('useMain-state', JSON.stringify(state))
}, { detached: true })
复制代码

ps: 可以查看pinia实例上的整个状态:

watch(
 pinia.state,
 (state) => {
   // 每当状态改变时,将整个状态保存到本地存储中
   localStorage.setItem('piniaState', JSON.stringify(state))
 },
 { deep: true }
)
复制代码

Getters

类似组件的computed 用于封装计算属性,有缓存的功能,getters的第一个参数是state。

1、声明一个getters 中的方法:

  /**
   * 类似组件的computed 用于封装计算属性,有缓存的功能
   */
  getters: {
    /**
     * 
     * @param state 函数接受一个可选参数:state 状态对象
     * 不使用state也可以使用 this
     * 如果使用了this 这必须手动制定函数的返回值的类型 否则类型推导不出来
     * @returns 
     */
    getCount(state){
      return state.countPinia +10
    },
    //返回值类型 **必须** 被明确地指定
    getCount2(): number {
      // 为整个存储(store)自动完成和类型注释 
      return this.countPinia +10
    },
  },
复制代码
👨‍🎓解析代码注意:

getters中的函数接受一个可选参数:state 状态对象

  • 不使用state也可以使用 this
  • 如果使用了this 这必须手动制定函数的返回值的类型 否则类型推导不出来

2、在组件中使用与state相同

<template>
<!-- state 中 -->
<p>{{useMain.countPinia}}</p>
<!-- getters 中 -->
<p>{{useMain.getCount}}</p>
</template>
复制代码

** 3、传递参数:利用高阶函数传递参数**

  /**
   * 类似组件的computed 用于封装计算属性,有缓存的功能
   */
  getters: {
    /**
     * 
     * @param state 函数接受一个可选参数:state 状态对象
     * 不使用state也可以使用 this
     * 如果使用了this 这必须手动制定函数的返回值的类型 否则类型推导不出来
     * @returns 
     */
    getCount(state){
      return state.countPinia +10
    },
     getCount2(state):Number{
      return (num)=> {
        return state.countPinia  + num
      } 
    }
  },
复制代码

组件中使用

 <p>{{useMain.getCount2(3)}}</p>
复制代码

4、访问其他store中的getters

例如我们声明了两个store

export const useMainStore = defineStore({
  id: "main",
  state: ()=>({
    return {countMain: 2}
  }),
  getters: {
    getCountMain(state){
      return state.countMain + 2
    }
  }
})
​
​
  export const useStore = defineStore({
    id: "user",
    state: ()=>({
         return { countUser: 2}
    }),
    getters: {
      addMain(state){
        const store = useMainStore()
        return state.countUser + store.countMain
      }
    }
 })
​
复制代码

5、在vue3组件中使用Composition Api

<script setup lang="ts">
import { storeToRefs,mapState  } from 'pinia'
import { useMainStore } from '@/store'
​
const store = useStore()
const { countPinia,getCountMain } = storeToRefs(store)
</script>
<template>
​
<p>{{countPinia}}</p>
<p>{getCountMain}}</p>
</template>
复制代码

6、vue2中 options API 的用法

import { mapState } from 'pinia'
import { useMainStore } from '@/store'
export default {
  computed: {
    // 允许访问组件内部的 this.doubleCounter 
    // 与从 store.doubleCounter 中读取一样
    //...mapState(useMainStore, ['getCountMain']),
    // same as above but registers it as this.myOwnName
    ...mapState(useMainStore, {
      myOwnName: 'doubleCounter',
      // 你也可以写一个函数以访问 store
      double: store => store.doubleCount,
    }),
  },
}
复制代码

Action

用于修改数据,有点儿类似 methods 的概念;

它们可以使用defineStore()的 actions属性进行定义,

异步和同步方法都可以使用,项目中的业务逻辑中方法可以用在这(这里与 Vuex 有极大的不同,Pinia 仅提供了一种方法来定义如何更改状态的规则,放弃 mutations 只依靠 Actions

import { defineStore } from "pinia";
​
// 1.定义容器
// 参数1:容器的ID,必须唯一 将来pinia会把所有的容易挂载到根容器
// 参数2:选项对象
// 返回值是一个函数 调用得到
export const useMainStore = defineStore("main", {
  /**
   * 类似于组件的data 用来存储全局状态
   * 1.必须是函数:这样是为了在服务器渲染的时候避免交叉请求导致的数据状态污染
   * 2. 必须还是箭头函数,这是为了更好的 TS 类型推导
   */
  state: () => {
    return {
      countPinia: 100,
      title: "pinia",
      arr: [1, 2],
    };
  },
​
  /**
   * 类似于组件的methods 封装有误逻辑 修改 state
   */
  actions: {
    // 注意:不能使用箭头函数定义action 因为使用箭头函数 函数内部的this指向就是外部
    changeState() {
      // this.countPinia++
      // this.title = "在action中修改title"
      // this.arr.push(3)
​
      this.$patch(state => {
        state.countPinia++;
        state.title = "修改";
        state.arr.push(3);
      });
    },
    changeState2(num:number){
      this.countPinia += num;
    }
  },
  
});
复制代码
👨‍🎓解析代码注意:

actions中的方法,可以通过 this 访问到整个存储实例,所以这个时候就不能使用箭头函数,因为箭头函数内部的this指向就是外部。

使用在Composition Api模式中使用

<script setup lang="ts">
import { storeToRefs,mapState  } from 'pinia'
import { useMainStore } from '@/store'
​
const store = useStore()
const { countPinia } = storeToRefs(store)
const clickEdit =()=>{
    store.changeState()
}
</script>
<template>
​
<p>{{countPinia}}</p>
<button @click="clickEdit">修改数据</button>
</template>
复制代码

options API 时的用法

import { mapActions } from 'pinia'
import { useMainStore } from '@/store'
export default {
  methods: {
    // 组件内部允许访问 this.changeState() 
    // 就像从 store.changeState() 调用一样
    ...mapActions(useMainStore, ['changeState']),
    // 与上面一样但是注册其为 this.myOwnName()
    ...mapActions(useMainStore, { myOwnName: 'changeState' }),
  },
}
复制代码

调用其他的action

export const useAppStore = defineStore({
  id: 'app',
  actions: {
    setData(data) {
      console.log(data)
      return data
    }
  }
})
export const useMainStore = defineStore({
  id: 'main',
  actions: {
    setData(data) {
        const appStore = useAppStore()
        return appStore.setData(data)
    }
  }
})
​
复制代码

订阅actions

$onAction() 详情可以:pinia.vuejs.org/core-concep…

插件

Pinia 存储(store)可以通过 低级API 完全扩展。以下是你可以执行的 action:

  • 存储(store) 添加新属性;
  • 当定义 存储 时,添加新选项;
  • 存储 添加新方法;
  • 包装现有方法;
  • 更改甚至取消动作(action);
  • 执行如本地存储等副效果;
  • 仅适用于特定存储

详情可以看:pinia.vuejs.org/core-concep…

持久化存储

插件 pinia-plugin-persist 可以辅助实现数据持久化功能。

安装

npm i pinia-plugin-persist --save
复制代码

使用

第一步:在src/store/index.ts

import { createPinia } from 'pinia'
import type   { App } from "vue";
import piniaPluginPersist from 'pinia-plugin-persist'
​
​
export function setupStore(app: App<Element>) {
    const pinia = createPinia();
    pinia.use(piniaPluginPersist);
    app.use(pinia);
}
复制代码

第二步:修改在入口main.ts的初始化配置pinia

import { createApp } from 'vue'
import App from './App.vue'
​
import { setupStore } from "@/store";
​
const app = createApp(App)
​
setupStore(app)
​
app.mount('#app')
复制代码

第三步:创建相应的store

src/store/app.ts

import { defineStore } from "pinia";
​
export const useAppStore = defineStore("app",{
  state: () => {
    return {
      name: "app store state: name",
    };
  },
  actions: {
    changeName() {
      this.$patch((state: { name: string; }) => {
        state.name = "修改";
      });
    },
  },
  // 开启数据缓存
  persist: {
    enabled: true,
  },
});
复制代码

第四步:使用

<script setup lang="ts">
import {useAppStore} from '@/store/app'
const appStore = useAppStore();
​
const clickEdit = ()=>{
   appStore.changeName()
}
</script>
​
<template>
​
​
<button @click="clickEdit">修改数据</button>
<hr>
<div>{{appStore.name}}</div>
​
</template>
复制代码

image.png

数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。

问:如果不想使用store中的id当做存储的可以了怎么办呢?

你可以自定义这个key,persist中有一个strategies 里自定义 key 值,并将存放位置由 sessionStorage 改为 localStorage。

persist: {
  enabled: true,
  strategies: [
    {
      key: 'my_store_app',
      storage: localStorage,
    }
  ]
}
复制代码

image.png

问:如果不想存储左右的状态state,只存储部分呢?

//src/store/app.ts
import { defineStore } from "pinia";
​
export const useAppStore = defineStore("app",{
  state: () => {
    return {
      name: "app store state: name",
      title:'标题',
      sub:'pinia',
      content:'本文是针对pinia的知识的分享。。。'
    };
  },
  actions: {
    changeName() {
      this.$patch((state: { name: string; }) => {
        state.name = "修改";
      });
    },
  },
  // 开启数据缓存
  persist: {
    enabled: true,
    strategies: [
      {
        key: 'my_store_app',
        storage: localStorage,
        paths: ['name', 'sub']
      }
    ]
  },
});
复制代码

image.png

感谢

到此,本篇文章先告一段落,如果有什么错误或不足,欢迎评论区指正!感谢您的阅读~~

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改