pinia状态管理库的使用

 注:本人使用vue3+js导入的pinia状态管理库,vue2请参考官方文档

pinia中文文档:https://pinia.web3doc.top/getting-started.html

第一步 使用 npm 或 yarn 安装

//使用npm安装
npm install pinia

//使用yarn安装
yarn add pinia

第二步

  安装完成后需要在main.js入口文件中引入并使用

// 文件名main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
//1、在入口文件引入 pinia 并使用createPinia
import {createPinia } from 'pinia'
// 2、使用createPinia函数创建出 pinia的实例
const pinia = createPinia()

function bootstrap(){
  const app = createApp(App)
  app.use(router)
// 3、在把 pinia挂载在vue身上
  app.use(pinia)
  app.mount('#app')
}
bootstrap()

第三步

在src目录下创建store文件夹

 创建完成后在store文件夹中创建.js为后缀的文件

 第四步

  4.1、在useOne.js中进行配置

// 1、引入并使用 defineStore 功能模块
import { defineStore } from 'pinia'

//2、创建一个容器  容器中有两个参数,参数一:容器的名称。参数二:容器的内容
//在pinia中只有 state  getters actions 
const useMainStore = defineStore('main', {
  // pinia状态管理中的state 通过箭头函数返回一个对象
  // state 相当于 vue中的data
  state: () => {
    return {
      name: '张三',
      age: 18
    }
  },
  //getters相当于 computed计算属性  getters中是有缓存的
  getters: {

  },
  //actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
  actions: {

  }
})


// 3、把容器暴露出去
export {
  useMainStore
}




注意:

1、需要导入defineStore方法来创建pinia来创建容器;

2、defineStore方法有两个参数

       1. 参数一:是一个字符串,自定义的容器名 (唯一的)

       2.参数二:是一个对象,pinia的配置都在这里面;

3、给容器命名的规范一般是:use+自定义的容器名+Store

4、最后将创建的容器进行导出;

4.2、使用store

src/components目录下创建一个新的vue文件:son1.vue

<template>

  <h2>{{mainStore.name}}</h2>
  <h2>{{mainStore.age}}</h2>

<button @click="getStore">点击</button>
</template>

<script setup>
  //1、导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

// 2、实例化容器
 const mainStore = useMainStore()

 //按钮点击事件
 function getStore(){
  console.log(mainStore.name + " " + mainStore.age);
 }


</script>

<style lang="scss" scoped>

</style>

 App.vue

<template>

  <Son1 />
  
</template>

<script setup>
import Son1 from '@/components/son1.vue';

</script>

<style lang="scss" scoped>

</style>

 

src/App.vue主页面中导入上述组件,在页面中进行显示:

注意:store 是一个reactive 包裹的对象,所有访问其中的成员不需要 .value

4.3、解构state 数据

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>

  <button @click="getStore">点击</button>
</template>

<script setup>
//1、导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

// 2、实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据
const { name, age } = mainStore

//按钮点击事件
function getStore() {
  console.log(name + " " + age);
}


</script>

<style lang="scss" scoped>

</style>

 来看下通过解构出来的state值和不通过解构得到的state值有什么区别:

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的{{ mainStore.age }}</h4>
  <h4>通过解构获得的{{ age }}</h4>

  <button @click="getStore">点击</button>

</template>

<script setup>
//1、导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

// 2、实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
const { name, age } = mainStore

//按钮点击事件
function getStore() {
  mainStore.age++
}



</script>

<style lang="scss" scoped>

</style>

通过上图可以看到:获取到state中的数据不是响应式的

如果想要解构拿到 Store 中的响应式数据可以使用 storeToRefs

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4>

  <button @click="getStore">点击</button>

</template>

<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)

//按钮点击事件
function getStore() {
  mainStore.age++
}

</script>

<style lang="scss" scoped>

</style>

 此时可以看到页面的数据已经变了,通过 storeToRefs 方法包裹pinia实例,再通过解构获取的state就是响应式的了。

使用 actions

src/store/useOne.js文件中的pinia实例中,创建一个actions方法:

// 1、引入并使用 defineStore 功能模块
import { defineStore } from 'pinia'

//2、创建一个容器  容器中有两个参数,参数一:容器的名称。参数二:容器的内容
//在pinia中只有 state  getters actions 
const useMainStore = defineStore('main', {
  // pinia状态管理中的state 通过箭头函数返回一个对象
  // state 相当于 vue中的data
  state: () => {
    return {
      name: '张三',
      age: 18
    }
  },
  //getters相当于 computed计算属性  getters中是有缓存的
  getters: {

  },
  //actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
  actions: {
    **
    addCount() {
      this.age++
    }
    **
  }
})

// 把容器暴露出去
export {
  useMainStore
}


src/components/App.vue页面组件中进行pinia的actions方法的调用,此处有三种调用的方式:

方法一: 在标签中绑定actions事件

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4>

  <button @click="getStore">点击</button>
   **<button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>**
</template>

<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)

//按钮点击事件
function getStore() {
  mainStore.age++
}

</script>

<style lang="scss" scoped>

</style>

 方法二: 自定义一个方法,在这个方法中去调用对应的actions方法:

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4>

  <button @click="getStore">点击</button>
   <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
   **<button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>**
</template>

<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)

//按钮点击事件
function getStore() {
  mainStore.age++
}
**// 自定义的 count 加法方法
const addCount = () => {
  mainStore.addCount()
}**

</script>

<style lang="scss" scoped>

</style>

 方法三: pinia中提供了一个方法$patch,向上面两种方法调用actions去改变state的时候,会有留下state值的历史记录(时间旅行)。但是如果不通过actions,而是直接去修改state的值的话,例如直接通过mainStore.age++这种方式修改state的值,就不会留下state的历史记录。而$patch方法可以直接去修改state中的值,并且留下历史记录:
 

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4>

  <button @click="getStore">点击</button>
   <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
   <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
</template>

<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)

//按钮点击事件
function getStore() {
  mainStore.age++
}
// 自定义的 count 加法方法
const addCount = () => {
  // mainStore.addCount()
  **// $patch 方法,可以直接修改 state 中的值
  mainStore.$patch({
    name: "徐福",
    age: 999,
  })**
}

</script>

<style lang="scss" scoped>

</style>

点击前

 点击后

 使用方法三的语法应用某些更改确实很困难或成本很高: 任何集合修改(例如,从数组中推送、删除、拼接元素)都需要您创建一个新集合。正因为如此,该 $patch 方法还接受一个函数来对这种难以用补丁对象应用的改变进行分组:

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4>

  <button @click="getStore">点击</button>
  <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
  <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
</template>

<script setup>
// 1、导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
//2、 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)

//按钮点击事件
function getStore() {
  mainStore.age++
}
// 自定义的 count 加法方法
// const addCount = () => {
//   // mainStore.addCount()
//   // $patch 方法,可以直接修改 state 中的值
//   mainStore.$patch({
//     name: "徐福",
//     age: 999,
//   })
// }
const addCount = () => {
  **// $patch 方法,通过分组改变 state 中的值
  mainStore.$patch(state => {
    state.name += '张三'
    state.age++
  })**
}
</script>

<style lang="scss" scoped>

</style>

你也可以完全自由地设置您想要的任何参数并返回任何内容。调用 actions 时,一切都会自动推断!

重置状态$reset

pinia的state更新的时候会有历史记录,即时间旅行,如果想要将数据重置到最开始更新数据的时候,pinia提供了一个方法:$reset

 

<template>

  <h2>{{name}}</h2>
  <h2>{{age}}</h2>
  <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4>

  <button @click="getStore">点击</button>
  <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
  <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
  **<button @click="resetCount">重置 state</button>**
</template>

<script setup>
// 导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()

//  解构获取state中的数据  解构出来的值不是响应式的
// 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)

//按钮点击事件
function getStore() {
  mainStore.age++
}
// 自定义的 count 加法方法
// const addCount = () => {
//   // mainStore.addCount()
//   // $patch 方法,可以直接修改 state 中的值
//   mainStore.$patch({
//     name: "徐福",
//     age: 999,
//   })
// }
const addCount = () => {
  // $patch 方法,通过分组改变 state 中的值
  mainStore.$patch(state => {
    state.name += '张三'
    state.age++
  })
}
**// 重置  数据的方法
const resetCount = () => {
  mainStore.$reset()
}**

</script>

<style lang="scss" scoped>

</style>

触发重置事件前

触发重置事件后

 

 跨容器调用

1、在pinia中没有modules概念,可以在pinia中同时创建多个容器实例;可以在每一个容器中分别调用其他容器中的值,进行一些列的操作;

2、首先在src/store/useOne.js文件中创建一个新的容器,在新的容器中可以在actions中,获取到其他容器实例,调用其中的state值

// 1、引入并使用 defineStore 功能模块
import { defineStore } from 'pinia'

//2、创建一个容器  容器中有两个参数,参数一:容器的名称。参数二:容器的内容
//在pinia中只有 state  getters actions 
const useMainStore = defineStore('main', {
  // pinia状态管理中的state 通过箭头函数返回一个对象
  // state 相当于 vue中的data
  state: () => {
    return {
      name: '张三',
      age: 18
    }
  },
  //getters相当于 computed计算属性  getters中是有缓存的
  getters: {

  },
  //actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
  actions: {
    addCount() {
      this.age++
    }
   
  }
})

const useProjectStore =  defineStore('project', {
   // pinia状态管理中的state 通过箭头函数返回一个对象
  // state 相当于 vue中的data
  state: () => {
    return {
      username: '李四',
      count: 21
    }
  },

  //getters相当于 computed计算属性  getters中是有缓存的
  getters: {

  },
  //actions相当于 methods 方法 用来封装业务逻辑 ,同步异步都支持
  actions: {
    // 1、加法方法
    addAge() {
      // 实例化 pinia 容器
      const mainState = useMainStore()
      this.count += this.count + mainState.age
    }
  }
})


// 把容器暴露出去
export {
  useMainStore,
  useProjectStore
}


3、在组件中可以有两种方法去调用pinia中跨容器调用的方法:

方法一: 直接在标签中去调用容器中的方法

<template>

  <!-- <h2>{{name}}</h2> -->
  <!-- <h2>{{age}}</h2> -->
  <!-- <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4> -->

  <!-- <button @click="getStore">点击</button>
  <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
  <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
  <button @click="resetCount">重置 state</button> -->
  **<h2>{{count}}</h2>**
  **<button @click="projectStore.addAge">模板跨容器调用</button>**
</template>

<script setup>
// 导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore ,useProjectStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()
**const projectStore = useProjectStore()**

//  解构获取state中的数据  解构出来的值不是响应式的
// 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
**const { username, count } = storeToRefs(projectStore)**

//按钮点击事件
// function getStore() {
//   mainStore.age++
// }
// 自定义的 count 加法方法
// const addCount = () => {
//   // mainStore.addCount()
//   // $patch 方法,可以直接修改 state 中的值
//   mainStore.$patch({
//     name: "徐福",
//     age: 999,
//   })
// }
// const addCount = () => {
//   // $patch 方法,通过分组改变 state 中的值
//   mainStore.$patch(state => {
//     state.name += '张三'
//     state.age++
//   })
// }
// 重置  数据的方法
// const resetCount = () => {
//   mainStore.$reset()
// }

</script>

<style lang="scss" scoped>

</style>

触发事件前

触发事件后

 方法二: 自定义一个调用容器方法的函数c

<template>

  <!-- <h2>{{name}}</h2> -->
  <!-- <h2>{{age}}</h2> -->
  <!-- <h4>没有通过解构获得的---{{ mainStore.age }}</h4>
  <h4>通过解构获得的---{{ age }}</h4> -->

  <!-- <button @click="getStore">点击</button>
  <button @click="mainStore.addCount">模板调用 actions 的 addCount 方法</button>
  <button @click="addCount">自定义方法调用 actions 的 addCount 方法</button>
  <button @click="resetCount">重置 state</button> -->
  <h2>{{count}}</h2>
  <button @click="projectStore.addAge">模板跨容器调用</button>
  **<button @click="addAge">自定义方法跨容器调用</button>**
</template>

<script setup>
// 导入pinia 中的 storeToRefs 方法
import { storeToRefs } from 'pinia';

//导入pinia实例 useMainStore是你在store中创建的容器名称
import { useMainStore ,useProjectStore } from '../store/useOne'

//实例化容器
const mainStore = useMainStore()
const projectStore = useProjectStore()

//  解构获取state中的数据  解构出来的值不是响应式的
// 将 pinia 实例对象通过 storeToRefs 包裹起来的时候,里面的值就是响应式的了
const { name, age } = storeToRefs(mainStore)
const { username, count } = storeToRefs(projectStore)

//按钮点击事件
// function getStore() {
//   mainStore.age++
// }
// 自定义的 count 加法方法
// const addCount = () => {
//   // mainStore.addCount()
//   // $patch 方法,可以直接修改 state 中的值
//   mainStore.$patch({
//     name: "徐福",
//     age: 999,
//   })
// }
// const addCount = () => {
//   // $patch 方法,通过分组改变 state 中的值
//   mainStore.$patch(state => {
//     state.name += '张三'
//     state.age++
//   })
// }
// 重置  数据的方法
// const resetCount = () => {
//   mainStore.$reset()
// }

// 自定义的  加法方法
**const addAge = () => {
  projectStore.count += mainStore.age
}**

</script>

<style lang="scss" scoped>

</style>

触发前

 

 触发后

 actions 的操作

const changeStore = () => {
  // 方式四:逻辑比较多的时候可以封装到 actions 做处理
  // 封装好 actions 之后,直接调用
  mainStore.adds(10)
}
  • 封装 actions:
  • // 类似与组件的 methods ,封装业务逻辑,修改 state 
    actions: {
      // 注意:不能使用箭头函数定义action,因为箭头函数绑定外部this
      adds(num) {      
        this.count = this.count + num
        this.foo++
        // 同样建议使用 $patch() 
        // this.$patch({})
        // this.Spatch(state = {……})
      }
    }
    

注意:像上面的跨容器调用的时候,将每一个容器都放在同一个文件中了,最好的做法需要将每个容器单独写一个文件。 

本文借鉴CSDN博主「凉爽爽爽爽爽爽爽爽爽」的原创文章
原文链接:https://blog.csdn.net/qq_45770253/article/details/123509563

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值