vue基础(第四章 Pinia)

1:Pinia 西班牙语:菠萝

1.1:Pinia是什么?

Pinia 是 Vue 官方新一代状态统一管理库,当数据需要在多个不相关的组件间共享的时候,需要使用Pinia,类似 Redis 集中缓存。专门为vue2和vue3设计,是Vuex 的替代方案。Vue 3 官方已推荐新项目直接使用 Pinia,不再主推 Vuex。

我们在上一章节的路由器中学习了组件之间传递数据,比如多层嵌套、兄弟组件、跨页面路由之间,数据传递会非常麻烦。很麻烦,但是pinia可以完美的结局这个问题

👉 Pinia:把公共数据放到全局仓库 (store)任意组件都可以直接读取、修改

F5 刷新页面:Pinia 清空,前端重新请求接口,再回填 Pinia。

补充:如果想让 Pinia 拥有类似 redis "持久化" 效果,前端可以搭配 pinia‑plugin‑persistedstate,把数据存到浏览器localStorage。localStorage 相当于浏览器本地小磁盘,但依然只属于这台电脑这个浏览器,别的设备访问不到,和后端 Redis 不是一回事。

1.2:有什么作用

管理跨组件共享全局状态

场景举例(工业后台 / MES 系统经常用到):

  1. 用户登录信息、token、角色权限、菜单列表
  2. 页面全局配置、筛选条件缓存
  3. 多个页面共享的设备列表、工单筛选参数
  4. 弹窗全局状态、消息通知

如果不用状态库:组件之间多层传参(props 层层传递),代码耦合严重; 使用 Pinia:任意组件直接读取 / 修改全局状态

1.3:Pinia 对比 Vuex 核心优势(面试必说)

移除了 Mutation Vuex:修改 state 必须走 mutation(同步)、action 处理异步,模板代码繁琐 Pinia:可以直接修改 state;异步逻辑写在 action 里,结构简单。

没有嵌套 modules Vuex 模块嵌套 store.user.token; Pinia 每个 store 是独立文件,扁平结构,导入即用,不用命名空间 namespaced。

原生 TypeScript 支持极好 类型自动推导,不需要额外复杂类型声明,非常适合 <script setup> + TS 项目。

代码更简洁,样板代码极少 不需要 commit、dispatch,降低学习成本。

支持组件外部调用 store 路由守卫、axios 拦截器里可以直接引入 store 操作状态(Vuex 也能实现,但 Pinia 更顺畅)。

Devtools 调试友好,支持时间旅行调试。

1.4:Pinia的核心状态

Pinia 三大核心概念

  1. state:状态,存放共享数据(等同于 Vuex 的 state)
  2. gettters:派生状态,相当于计算属性,有缓存
  3. actions:修改状态方法,支持同步、异步(替代 Vuex mutation + action)

2:实战开始

2.1:使用pinia之前,组件count.vue

html 复制代码
<template>
    <div>
        <h1>pinia的person组件</h1>
        <h2>计数器:{{ count }}</h2>
        名字:<input type="text" v-model="name">{{ name }}
        <hr>

        <!-- v-model双向数据绑定。影响value属性  -->
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="add">+数字</button>
        <button @click="minus">-数字</button>


    </div>

</template>

<script setup lang="ts">
import { ref } from 'vue';

let name = ref("张三");
console.log(name);

// 计数器方法
let count = ref(0);
let n = ref(1);
function add() {
    count.value += n.value;

}

function minus() {
    count.value -= n.value;
}


</script>

<style></style>

2.2:使用pinia做状态集中管理

1:首先安装pinia

html 复制代码
npm install pinia

2:在main.ts中使用pinia

TypeScript 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
//创建pinia
const pinia = createPinia()
//使用pinia
app.use(pinia)

app.mount('#app')

2.3:新建store下的count.ts 操作pinia

TypeScript 复制代码
import { defineStore } from "pinia";

//定义仓库
const userCountStore = defineStore("count", {
  //状态 state,存放共享数据(等同于 Vuex 的 state)
  state() {
    //返回数据
    return {
      name:"张三",
      count: 0,
      n: 1,
    };
  },

  // Actions:修改状态的方法,支持同步/异步(替代Vuex mutation+action)
  actions: {
    add2():void {
      this.count += this.n;
    },
    minus2() {
      this.count -= this.n;
    },
    // 异步示例
    async changeName(newName: string) {
      // 可以在这里请求后端接口
      this.name = newName;
    },
  },
});

//导出仓库 默认单利,多组件共享
//export default userCountStore;
export { userCountStore };

2.4:count.vue组件使用pinia

html 复制代码
<template>
    <div>
        <h1>pinia的person组件</h1>
        <h2>计数器:{{ count }}</h2>
        名字:<input type="text" v-model="name">{{ name }}
        <hr>

        <!-- v-model双向数据绑定。影响value属性  -->
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="add">+数字</button>
        <button @click="minus">-数字</button>
        <hr>
        <h1>使用pinia</h1>

        <h2>计数器:{{ countStore.count }}</h2>



        <!-- v-model双向数据绑定。影响value属性  -->
        <select v-model.number="countStore.n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="add1">+数字</button>
        <button @click="minus1">-数字</button>

        <hr>
        <button @click="add11">+数字</button>
        <button @click="minus11">-数字</button>

        <hr>

    </div>

</template>

<script setup lang="ts">
import { ref } from 'vue';
import { userCountStore } from '../store/count'

let name = ref("张三");
console.log(name);

//1:不实用pinia 计数器方法
let count = ref(0);
let n = ref(1);
function add() {
    count.value += n.value;

}

function minus() {
    count.value -= n.value;
}

//2:使用pinia, 得到单利的countStore
let countStore = userCountStore()
function add1() {
    countStore.count += countStore.n;
}

function minus1() {
    countStore.count -= countStore.n;
}
function add11() {
    //通过仓库调用方法
    countStore.add2();
}
function minus11() {
    //通过仓库调用方法
    countStore.minus2();
}

</script>

<style></style>

2.5:storeToRefs

storeToRefs 是 Pinia 提供的工具函数,专门用来安全解构 Store 中的 state、getter,保证解构出来的变量依旧保留响应式。

html 复制代码
<template>
    <div>
        <h1>pinia的person组件</h1>
        <h2>计数器:{{ count }}</h2>
        名字:<input type="text" v-model="name">{{ name }}
        <hr>

        <!-- v-model双向数据绑定。影响value属性 
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="add">+数字</button>
        <button @click="minus">-数字</button> -->
        <hr>
        <h1>使用pinia</h1>

        <h2>计数器:{{ count }}</h2>
        <!-- v-model双向数据绑定。影响value属性  -->
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="add1">+数字</button>
        <button @click="minus1">-数字</button>

        <hr>
        <button @click="add11">+数字</button>
        <button @click="countStore.minus2">-数字</button>

        <hr>

    </div>

</template>

<script setup lang="ts">
import { ref } from 'vue';
import { userCountStore } from '../store/count'
import { storeToRefs } from 'pinia';

let name = ref("张三");
console.log(name);

// //1:不实用pinia 计数器方法
// let count = ref(0);
// let n = ref(1);
// function add() {
//     count.value += n.value;

// }

// function minus() {
//     count.value -= n.value;
// }

//2:使用pinia, 得到单利的countStore
let countStore = userCountStore()
//storeToRefs结构才能响应式 
let {count,n}=storeToRefs(countStore);
//这两个对象也有了响应式
function add1() {
    countStore.count += countStore.n;
}

function minus1() {
    countStore.count -= countStore.n;
}
function add11() {
    //通过仓库调用方法
    countStore.add2();
}
function minus11() {
    //通过仓库调用方法
    countStore.minus2();
}

</script>

<style></style>

2.6:pinia持久话,因为页面刷新数据会丢失

1:安装持久化插件

html 复制代码
npm install pinia-plugin-persistedstate

2:main.ts 注册插件

TypeScript 复制代码
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

3:仓库开启持久化:

TypeScript 复制代码
export const usePersonStore = defineStore('person', {
  state: () => ({...}),
  getters:{},
  actions:{},
  persist: true // 开启持久化
})

3:案例

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A1 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄1 天前
JavaScript 隐式全局变量解析
javascript
honkun61 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19911 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net