Skip to content

介绍

  1. Pinia 一个全新的 Vue 状态管理工具。
  2. Pinia 是下一代的 Vuex,可以取代 Vuex。
  3. 官网:https://pinia.vuejs.org/zh/
  4. Vue2 和 Vue3 都支持,更倾向于 Vue3。
  5. 支持浏览器的 VueDevTools 调试工具。
  6. 支持模块化热更新。
  7. 支持使用插件扩展。

核心概念

  1. Pinia 开发思想于 Vuex 差不多,比 Vuex 更简单。
  2. Vuex 中核心概念有 4 个:State、Getters、Actions、Mutations。
  3. Pinia 中核心概念有 3 个:State、Getters、Actions。
  4. Vuex 中的 Actions 只能异步处理逻辑,在 Pinia 中 Actions 既可以异步也可以同步。

快速上手

安装

sh
npm i pinia

入口文件

js
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';

const app = createApp(App);
app.use(createPinia());		// createPinia 用于创建 Pinia 实例
app.mount('#app');

容器代码

js
import { defineStore } from "pinia";

/**
 * 定义并导出容器
 * 参数1:容器 ID,必须唯一
 * 参数2: 选项对象
 * 返回值是一个函数,调用函数返回容器实例
 */
export const UserStore = defineStore('user', {
    /**
     * 数据容器,类似于组件的 data
     * 必须是箭头函数
     */
    state: () => ({
        count: 100,
        total: 20
    }),
    
    /**
     * 类似于组件的 computed,用来封装计算属性,有缓存功能
     */
    getters: {},
    
    /**
     * 类似于组件的 methods,用来处理业务逻辑
     * 内部不能写箭头函数,this 指向会变
     */
    actions: {}
})

组件中使用

vue
<template>
	<h3>count: {{ count }}</h3>
	<h3>total: {{ total }}</h3>
</template>

<script setup>
import { storeToRefs } from "pinia";
import { UserStore } from "./store";

let { count, total } = storeToRefs(UserStore());
</script>

修改容器中的数据

准备组件及容器

vue
<template>
	<h3>姓名: {{ name }}</h3>
	<h3>年龄: {{ age }}</h3>
	<h3>爱好: {{ hobby }}</h3>
	<button @click="changeInfo">修改信息</button>
</template>

<script setup>
import { storeToRefs } from "pinia";
import { UserStore } from "./store";

const store = UserStore();
const changeInfo = () => {
	
}
let { name, age, hobby } = storeToRefs(store);
</script>
js
import { defineStore } from "pinia";

export const UserStore = defineStore('user', {
    state: () => ({
        name: 'iGma',
        age: 20,
        hobby: []
    })
})

方式一:直接修改

js
const store = UserStore();
const changeInfo = () => {
	store.name += '~';
	store.age += 10;
	store.hobby.push(10);
}

方式二:$patch 批量更新

js
const store = UserStore();
const changeInfo = () => {
	store.$patch({
		name: store.name += '~',
		age: store.age += 10,
		hobby: [...store.hobby, 10]
	})
}

方式三:$patch 函数

js
const store = UserStore();
const changeInfo = () => {
	store.$patch(state => {
		state.name += '~';
		state.age += 10;
		state.hobby.push(10);
	})
}

方式四:在 Actions 中封装方法

js
const store = UserStore();
const changeInfo = () => {
	store.updateState();
}
js
import { defineStore } from "pinia";

export const UserStore = defineStore('user', {
    state: () => ({
        name: 'iGma',
        age: 20,
        hobby: []
    }),
    actions: {
        updateState() {
            this.name += '~';
            this.age += 10;
            this.hobby.push(10);
        }
    }
})

getter 用法

和 Vuex 一样,用的不多。

vue
<template>
	<h3>姓名: {{ name }}</h3>
	<h3>年龄: {{ age }}</h3>
	<h3>爱好: {{ hobby }}</h3>
	<h3>爱好和: {{ sumHobby }}</h3>
	<button @click="changeInfo">修改信息</button>
</template>

<script setup>
import { storeToRefs } from "pinia";
import { UserStore } from "./store";

const store = UserStore();
const changeInfo = () => {
	store.updateState();
}
let { name, age, hobby, sumHobby } = storeToRefs(store);
</script>
js
import { defineStore } from "pinia";

export const UserStore = defineStore('user', {
    state: () => ({
        name: 'iGma',
        age: 20,
        hobby: []
    }),
    actions: {
        updateState() {
            this.hobby.push(10);
        }
    },
    getters: {
        sumHobby() {
            let sum = 0;
            this.hobby.forEach(item => {
                sum += item;
            })
            return sum;
        }
    }
})

storeToRefs 用法

假设某个 pinia 身上有很多数据,这是我们想在组件中结构赋值并保证数据的响应式建议使用 Pinia 提供的 storeToRefs 而不是 Vue3 提供的 toRefs

js
import { defineStore } from "pinia";

export const UserStore = defineStore('user', {
    state: () => ({
        name: 'iGma',
        age: 20,
        hobby: []
    }),
})
vue
<script setup>
import { storeToRefs } from "pinia";
import { UserStore } from "./store";

const store = UserStore();
let { name, age, hobby } = storeToRefs(store);
</script>

$subscribe

当我们创建一个 Pinia 实例对象时,可以使用对象身上的 $subscribe 方法监听数据的变化。

vue
<script setup lang="ts">
import {userStore} from '@/pinia/user';
import {storeToRefs} from "pinia";

let user = userStore();
let {name, age, gender} = storeToRefs(user);

function changeAge() {
    user.age += 1;
}

user.$subscribe((mutation, state) => {
    console.log('mutation', mutation);
    console.log('state', state);
})
</script>

<template>
    <p>用户名:{{name}}</p>
    <p>年龄:{{age}}</p>
    <p>性别:{{gender}}</p>
    <button @click="changeAge">修改年龄</button>
</template>

基于 MIT 许可发布