pinia状态管理仓库

发布于:2025-07-04 ⋅ 阅读:(14) ⋅ 点赞:(0)

前言:

        pinia是vue3发布之后对vuex的一个升级版本,它们有一些相似之处,总之非常好用,接下来我就来一步一步创建我的pinia仓库并比较它与vuex有哪些不同。

实现步骤

1.下载依赖

npm:

npm install pinia

pnpm:

pnpm install pinia

yarn:

yarn add pinia

        建议使用pnpm或yarn下载依赖,因为npm会产生一些幽灵依赖。

2.在main.js中使用

import { createPinia } from 'pinia'

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)

3.创建仓库文件(Options API风格)

        一般情况下,会在src目录下创建一个stores文件夹,在该文件夹中去创建状态管理仓库。代码如下:

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('num', {
    state: () => {
        return {}
    },
    getters: {},
    actions: {}
})

        现在就创建好了一个基本的状态管理创库了,首先直观的可以观察到与vux不同的是pinia没有modules,只有state、getters、actions。

        其次在vuex中state是一个对象,而pinia则是一个函数。

4.state

export const useCounterStore = defineStore('user', {
    state: () => {
        return {
            userName: '张三',
            age: 18
        }
    },
    getters: {},
    actions: {}
})

        不过,不管是vuex还是pinia,定义的数据都放在state中,我这边就随便定义了两个数据。接下来我们就要在组件中去使用我们定义的数组

1.在组件中使用

<template>
  <div class="app">
    <div>name : {{ user.userName }}</div>
    <div>age : {{ user.age }}</div>
    <button @click="handleAge">点击</button>
  </div>
</template>

<script setup>
import { useCounterStore } from './stores/user'
const user = useCounterStore()
const handleAge = () => {
  user.age = 20;
}
</script>

        以上就将创建好的状态仓库导入到了组件中,我们也可以通过方法直接改变定义数据的值,而vuex需要通过mutations进行提交。

        也可以使用解构的方式获取到状态仓库中的数据。

<template>
  <div class="app">
    <div>name : {{ userName }}</div>
    <div>age : {{ age }}</div>
    <button @click="handleAge">点击</button>
  </div>
</template>

<script setup>
import { useCounterStore } from './stores/user'
const store = useCounterStore()
const { userName, age } = store
const handleAge = () => {
  age = 20;
}
</script>

        但解构之后,发现点击按钮之后会报错,无法修改数据了,这是因为当我们解构之后这个数据不是响应式数据,因此当我们解构的时候需要做另外的操作,使用到了storeToRefs API。

<template>
  <div class="app">
    <div>name : {{ userName }}</div>
    <div>age : {{ age }}</div>
    <button @click="handleAge">点击</button>
  </div>
</template>

<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from './stores/user'
const store = useCounterStore()
const { userName, age } = storeToRefs(store) 
const handleAge = () => {
  age.value = 20;
}
</script>

        这样解构之后的数据依然是响应式数据。

2.批量更新

        当我们需要对多个数据进行批量操作时,代码如下

<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from './stores/user'
const store = useCounterStore()
const { userName, age } = storeToRefs(store)
const handleAge = () => {
  // 批量操作
  // 第一种方式:
  // userName.value = '李四'
  // age.value++
  // 第二种方式:
  store.$patch(state => {
    state.userName = '李四'
    state.age++
  })
}
</script>

3.总结:

来总结一下state在pinia和vuex中的不同:

1.写法上:pinia中state是一个函数,而vuex中state是一个对象;

2.修改数据:pinia中可以直接修改state的数据,而vuex中不可以直接修改state中的数据,需要通过mutation提交才可以。

5.getters

        getters作为一个计算属性,并且有缓存机制,与vuex几乎一样。

export const useCounterStore = defineStore('user', {
    state: () => {
        return {
            userName: '张三',
            age: 18
        }
    },
    getters: {
        setAge(){
            // 打印 缓存机制
            console.log('getters');
            return this.age + 100;
        }
    },
    actions: {}
})

        我在getters中写了一个计算属性setAge,它做的事就是将age加100,并且我打印了一条数据,是为了证明它有缓存。

<template>
  <div class="app">
    <div>name : {{ userName }}</div>
    <div>age : {{ age }}</div>
    <div>{{ setAge }}</div>
    <div>{{ setAge }}</div>
    <div>{{ setAge }}</div>
    <div>{{ setAge }}</div>
    <button @click="handleAge">点击</button>
  </div>
</template>

<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from './stores/user'
const store = useCounterStore()
const { userName, age, setAge } = storeToRefs(store)
const handleAge = () => {
  // 批量操作
  // 第一种方式:
  // userName.value = '李四'
  // age.value++
  // 第二种方式:
  store.$patch(state => {
    state.userName = '李四'
    state.age++
  })
}
</script>

 

        这边我将setAge渲染了多次 ,但控制台只打印了一次,因为getters是有缓存机制的。

6.actions

        actions是用来写方法的,它支持同步以及异步。

actions: {
        getAge(val) {
            this.age += val
        }
    }

        定义一个方法,这个方法接收一个参数,执行一次将age增加一次对应参数的值,在组件中使用这个方法。

<button @click="handleAdd">增加</button>

const handleAdd = () => {
  store.getAge(2)
}

        新增加一个按钮,给按钮绑定点击事件,点击一次就执行一次actions中的getAge。

        以上基本的一个实现思路就完成了,不过创建仓库还有第二种写法。

第二种创建状态仓库的方式(Composition API风格)

        在上一种方式中,defineStore的第二个参数是数组,它也可以是一个函数,当第二个参数是一个函数时,写法就发生了区别,以下我将上面演示的小例子改为第二种写法。代码如下:

import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('num', () => {
    const userName = ref('张三')
    const age = ref(18)
    const setAge = computed(() => age.value + 100)
    function getAge(val) {
        age.value += val
    }
    return { userName, age, setAge, getAge }
})

        这种方式更符合vue3的书写习惯,说的通俗易懂就是ref相当于state,computed相当于getters,function相当于action。

        这两种的效果是一样的,具体使用哪种看你的书写习惯。

结语:

        Pinia作为Vue3的官方推荐状态管理库,以其简洁的API设计和更好的TypeScript支持,显著提升了开发体验。通过对比Vuex,Pinia的优势主要体现在以下方面:

        Pinia取消了Vuex中繁琐的modules概念,简化了状态组织的复杂度。其state采用函数式返回,更契合Composition API的设计理念,而Vuex的state是直接定义的对象结构。

        Pinia允许直接修改state数据,无需通过mutations提交,大幅减少模板代码。getters的缓存机制与Vuex一致,但通过Composition API的computed实现更直观。actions同时支持同步和异步操作,与组件逻辑无缝衔接。

        两种仓库创建方式(Options API风格与Composition API风格)为开发者提供了灵活性,后者尤其适合Vue3的响应式编程范式。storeToRefsAPI解决了响应式数据解构的痛点,体现了Pinia对开发者体验的深度优化。

        总体而言,Pinia在保留状态管理核心功能的同时,通过更现代的设计降低了学习成本,是Vue3项目状态管理的理想选择。