探索 Pinia:Vue.js 状态管理的现代替代品

647 阅读4分钟

上篇文章介绍了父子组件之间的通信,但是当碰到爷孙组件或者兄弟组件时,使用父子组件之间的Props等方法就要一层一层传递,非常麻烦且不优雅,但是有个非常简洁的方法可以解决,那就是今天要介绍的菠萝了。

今天就让我们通过一个小demo来认识一下pinia在仓库中的概念,Pinia 就是一个用于 Vue.js 应用程序的轻量级状态管理库,可用于跨组件,页面进行状态共享

比如;写一个简单的购物车,实现以下效果。 PixPin_2024-12-18_23-36-21.gif

当然,实现上面效果只需要用一个组件或一个页面就可以完成,但是我们可以通过这个简单的例子来了解 pinia 的用法,实现跨组件状态共享,就把上面的商品列表写在List.vue组件上,下面的商品数量统计和合计写在Car.vue组件上,如下。

image.png

需要实现点击每个加入购物车,购物车中的商品数量以及合计会跟着发生变化,我们就需要用到仓库的概念,创建一个仓库,将共用的数据放到仓库里面,取数据时再到仓库中去取。

创建仓库就可以使用到 pinia 状态管理库,那么这个 pinia 怎么用呢?

基本步骤

  1. 安装pinia
npm install pinia

2. 创建 pinia 实例,在项目的 store 文件夹中创建一个 index.js 文件,并初始化 pinia 实例。这个只是为了让pinia的源代码跟vue的源代码可以融合使用。

import { createPinia } from 'pinia'
const store = createPinia()

export default store

3. 然后在main.js全局里面use它全局生效,这样项目里每个地方都可以使用这个仓库了。

import store from './store/index.js'
createApp(App).use(store)

4. 在store下面创建一个car.js,在里面开创一个可用的仓库,将商品列表的数据数组放入这个仓库,defineStore执行结果是一个函数体。

import { defineStore } from 'pinia'   // 开创一个可用的仓库
export const useCarStore = defineStore('car', () => {
  state:()=>{
    return {
      listArr:[xxx]
    }
  }
}
export default useCarStore   // 抛出这个仓库

image.png

  1. 然后就是如何将它取出来用了。在List.vue中引入这个仓库。
import useCarStore from '../store/car.js'
const carStore = useCarStore()   // useCarStore是一个函数

打印出这个carStore如下;

image.png

这样就可以把仓库中的数据取出来了。直接使用carStore.listarr就是这个数组了,然后直接将它循环就可以渲染到页面上了。

pinia 的使用

上面的是老版本vuex的写法,pinia的前身就是vuex。

在pinia中:

  • ref() 就是 state 属性
  • computed() 就是 getters
  • function() 就是 actions

显然新的语法更符合vue的语法。所以我们使用新的语法,同样defineStore先接收一个唯一的id,然后接收一个回调函数,里面可以直接定义数组,然后再return出这个数组,然后List.vue中就可以直接carStore.listArr获取这个数组。

export const useCarStore = defineStore('car', ()=>{
    const listArr=[]
    
    return {
        listArr
    }
})

然后回到我们的购物车,直接将定义在仓库中的listArr通过v-for遍历渲染到页面上,然后给加入购物车这个按钮绑定点击事件,并且传入该物品的信息(item)。

<template>
  <div>
    <ul>
      <li v-for="(item, i) in carStore.listArr" :key="index">
        <img :src="item.pic" alt="">
        <p> {{ item.name }}</p>
        <p>{{ item.desc }}</p>
        <div class="price">
          <span>{{ item.price }}</span>
          <button @click="addCar(item)">加入购物车</button>
        </div>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { useCarStore } from '../store/car.js'
const carStore = useCarStore()

console.log(carStore.listArr);

const addCar = (item) => {
  carStore.addSelectArr(item)   // 调用仓库中的方法
}

</script>

然后在仓库中定义addSelectArr函数。

// 需要注意要将其设置成响应式
const selectArr = reactive([])  // 选中的商品,用来后面计算商品数量和总价

const addSelectArr = (item) => {
    selectArr.push(item)
  }

然后就是在仓库中定义两个变量用来计算商品数量和商品总价。

const selectNum = computed(() => {
    return selectArr.length
  })
const totalPrice = computed(() => {
    let totalPrice = 0;  // 总价
    for (let i = 0; i < selectArr.length; i++) {
      totalPrice += selectArr[i].price
    }
    return totalPrice;
  })

最后在Car.vue中渲染selectNum和totalPrice

image.png

仓库中的代码如下;

image.png

这样就使用pinia完成这个小demo了。

注意:

  • 俩个组件之间想要实现数据共用,就将数据定义在仓库当中,然后俩个组件各自引入同一个仓库对象
  • 仓库中的数据修改,应该使用仓库中的方法进行修改,而不要将数据引入到组件中后修改

好了,通过这个简单的购物车示例,我们了解了 Pinia 的基本用法,还体会到了它在 Vue.js 应用中实现跨组件状态共享的便捷性,当有爷孙等多层组件或兄弟组件之间的通信就可以使用这个菠萝了,最后。

image.png