pinia简单使用

391 阅读3分钟

~~我正在参加「掘金·启航计划」~~

ps:以下代码环境均基于vue3,具体信息可参考pinia中文官网

1. pinia安装

 npm i pinia

2. 引入pinia

main.jsmain.ts中将pinia注册到vue实例

 import { createApp } from 'vue'
 // 导入创建pinia实例的方法 createPinia
 import { createPinia } from 'pinia'
 import App from './App.vue'
 ​
 const app = createApp(App)
 // 将创建的实例注册到vue实例中
 app.use(createPinia())
 app.mount('#app')

3. 创建pinia模块

每个pinia模块由一个唯一标识表示,包含三个概念:state、getters、actions。其中state相当于组件的“数据“,getters相当于组件中的“计算属性”,actions相当于组件中的”方法“。

一般会在src目录下新建一个store文件夹,来存放定义的pinia模块,如下所示,定义了一个counter.js文件,即counter模块,

 import { defineStore } from 'pinia'
 ​
 // 第一个参数是模块名称,唯一标识该模块,第二个参数为一个包含state、getters、actions属性的对象
 export const useStore = defineStore('counter', {
   state() {     // 定义状态属性的方法,返回值为定义的状态属性对象
     return {
       count: 0,
       count1: 10
     }
   },
   getters: {    // 相当于组件中的计算属性,可以缓存数据
 ​
   },
   actions: {    // 相当于组件中的方法,多用于修改状态属性值
     
   }
 })

4. pinia的使用

4.1 vue模块中的简单使用

 <template>
   <div>
     <button>{{store.count}}</button>
     <h2>{{store.count1}}</h2>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 ​
 const store = useStore()
 </script>

注意:store 是一个用reactive 包裹的对象,这意味着不需要在getter 之后写.value,但是,就像setup 中的props 一样,我们不能对其进行解构

如果想要解构后直接访问,那么可以借助storeToRefs()方法,具体用法如下:

 <template>
   <div>
     <button>{{count}}</button>
     <h2>{{count1}}</h2>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 import { storeToRefs } from 'pinia';
 ​
 const store = useStore()
 ​
 // 通过storeToRefs实现store对象的解构
 const {count, count1} = {...storeToRefs(store)}
 </script>

注意:storeToRefs只能解构响应式属性,跳过任何 action 或 非响应式(不是 ref/reactive)的属性

4.2 修改pinia状态属性的值

4.2.1 直接修改

 <template>
   <div>
     <button @click="add">{{count}}</button>
     <h2>{{count1}}</h2>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 import { storeToRefs } from 'pinia';
 ​
 const store = useStore()
 ​
 // 通过storeToRefs实现store对象的解构
 const {count, count1} = {...storeToRefs(store)}
 ​
 const add = () => {
   // 若使用的解构后的对象,则需要通过.value获取值
   count.value++
   // 直接通过store获取对象
   store.count1++
 }
 </script>

4.2.2 通过$patch方法修改

1、传递对象修改

 <template>
   <div>
     <button @click="add">{{count}}</button>
     <h2>{{count1}}</h2>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 import { storeToRefs } from 'pinia';
 ​
 const store = useStore()
 ​
 // 通过storeToRefs实现store对象的解构
 const {count, count1} = {...storeToRefs(store)}
 ​
 const add = () => {
   store.$patch({
     count: store.count + 1,     // 注意:这里不能使用++,因为是把store.count+1的值赋给count,而不是它自身
     count1: store.count1 + 10
   })
 }
 </script>

2、传递函数修改

 <template>
   <div>
     <button @click="add">{{count}}</button>
     <h2>{{count1}}</h2>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 import { storeToRefs } from 'pinia';
 ​
 const store = useStore()
 ​
 // 通过storeToRefs实现store对象的解构
 const {count, count1} = {...storeToRefs(store)}
 ​
 const add = () => {
   store.$patch((state) => {
     state.count++
     state.count1 += 10
   })
 }
 </script>

看到这里,可能觉得通过$patch修改的方式没有第一种方式简单,确实如此,不过$patch也有它的优势,不然存在的意义何在呢?是吧

用官方干的说法就是:针对$patch做了特殊优化的,怎么个特殊法,咋也不知道,希望有大神指点一二。

4.2.3 通过actions定义函数修改

对于复杂的业务逻辑,我们一般不在vue模板中修改状态属性值,而是在actions中定义方法来修改状态属性,这样方便维护。

 import { defineStore } from 'pinia'
 ​
 // 第一个参数是模块名称,唯一标识该模块,第二个参数为一个包含state、getters、actions属性的对象
 export const useStore = defineStore('counter', {
   state() {     // 定义状态属性的方法,返回值为定义的状态属性对象
     return {
       count: 0,
       count1: 10
     }
   },
   getters: {    // 相当于组件中的计算属性,可以缓存数据
 ​
   },
   actions: {    // 相当于组件中的方法,多用于修改状态属性值
     increment() {
       this.count++
       this.count1 += 10
     }
   }
 })
 <template>
   <div>
     <button @click="store.increment">{{count}}</button>
     <h2>{{count1}}</h2>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 import { storeToRefs } from 'pinia';
 ​
 const store = useStore()
 ​
 // 通过storeToRefs实现store对象的解构
 const {count, count1} = {...storeToRefs(store)}
 ​
 const add = () => {
   store.$patch((state) => {
     state.count++
     state.count1 += 10
   })
 }
 </script>

4.3 重置状态

执行调用store对象的$reset()方法即可,如下:

 <template>
   <div>
     <button @click="store.increment">{{count}}</button>
     <h2>{{count1}}</h2>
     <button @click="store.$reset()">reset</button>
   </div>
 </template>

4.4 替换状态

修改store对象的$state属性即可,如下:

 <template>
   <div>
     <button @click="store.increment">{{count}}</button>
     <h2>{{count1}}</h2>
     <button @click="store.$reset()">reset</button>
     <br>
     <button @click="store.$state = newState">newState</button>
   </div>
 </template>
 ​
 <script setup>
 // 导入我们counter模块定义的 store变量,该变量是一个方法,调用后返回一个能直接访问状态属性和定义的方法的对象
 import { useStore } from '@/stores/counter'
 import { storeToRefs } from 'pinia';
 ​
 const store = useStore()
 ​
 // 通过storeToRefs实现store对象的解构
 const {count, count1} = {...storeToRefs(store)}
 ​
 const add = () => {
   store.$patch((state) => {
     state.count++
     state.count1 += 10
   })
 }
 ​
 const newState = {
   count: 99999,
   count1: 100000
 }
 </script>

4.5 getters属性

Getter 完全等同于 Store 状态的计算属性,支持常规函数和箭头函数。

使用常规函数时可以通过 this 访问到 整个 store 的实例;使用箭头函数时,通过”状态“参数来获取属性。

 // 常规函数方式
 getters: {  // 相当于组件中的计算属性,可以缓存数据
   doubleCount() {
     return this.count * 2       //通过this方法状态属性
   },
   doubleCountPlusOne() {
     return this.doubleCount + 1     // 通过this访问前面定义的计算属性
   } 
 }
 ​
 // 箭头函数方式
 getters: {
   doubleCount: (state) => state.count * 2,      // 通过state参数访问状态属性
   doubleCountPlusOne: (state) => {
     return state.doubleCount + 1            // 通过state参数访问前面定义的计算属性
   } 
 }
 <template>
   <div>
     <button @click="store.increment">{{count}}</button>
     <h2>{{count1}}</h2>
     <button @click="store.$reset()">reset</button>
     <br>
     <button @click="store.$state = newState">newState</button>
     <h1>{{store.doubleCount}}</h1>
     <h1>{{store.doubleCountPlusOne}}</h1>
   </div>
 </template>

4.6 state方法

state方法除了声明为常规函数外,也可以声明为箭头函数。箭头函数写起来更简单,如下:

 state: () => ({
   count: 0,
   count1: 10
 })

\