引言
哈喽,各位小伙伴!👋 作为一名大三的“资深”前端小白,最近我可是被 Vue 的状态管理搞得焦头烂额。父子组件传值?兄弟组件通信?简直是把人绕进了一个“props 地狱”!🤯 就在我快要放弃的时候,Pinia 这个“大救星”出现了!😎 今天就来和大家聊聊这个拯救我于水火之中的状态管理库——Pinia!
今天我们的实验结果如图:
这种组件套组件的前端架子,按照我们曾经的经验就是,一直疯狂地props和emit,这样我们写出来的就是屎山代码。
为什么我们需要 Pinia?🤔
首先,我们来回顾一下,在没有 Pinia 的日子里,我们是怎么处理组件之间共享状态的?
- 父传子,子传父: 就像小时候玩“传话筒”游戏,数据一层一层地传递,稍微多几个组件就乱成一锅粥,谁都不知道数据最终跑到哪里去了。而且子组件还只能“老老实实”地接收父组件传来的 props 数据,想改?没门儿!🙅♀️
- 兄弟组件通信: 这更头疼!要先传给父组件,再由父组件传给另一个兄弟组件,中间人都要累趴下! 😫
所以,当组件层级复杂,需要共享的数据越来越多时,这种方式简直就是一场灾难!💔
(小 tips:正如代码中的注释: “<!-- <CompA :count="count" @add="increment"/> -->” 这种传统的父子传值方式,当组件嵌套较深时,会变得非常繁琐,维护起来也很痛苦。所以,我们需要一个更优雅的解决方案!)
Pinia:状态管理界的“共享单车”!🚴♀️
Pinia 的出现,就是来解决这个问题的!它就像共享单车,把状态数据集中管理起来,让各个组件都能随时取用,还能随时修改,简直不要太方便!🥳
Pinia 的核心思想:集中式状态管理!
Pinia 的核心在于 Store(仓库) 。你可以把 Store 想象成一个存放你所有共享状态数据的仓库。这个仓库里的数据,就像共享单车一样,每个组件都可以随时来“借用”和“归还”。
Pinia 上手:三步搞定!🚶♂️🚶♀️🚶
Pinia 用起来超级简单,只需三步:
-
安装 Pinia:
npm install pinia -
创建 Pinia 实例并注入到 Vue 应用中:
在你的
main.js文件中:import { createApp } from 'vue' import App from './App.vue' // vue 全家桶的最后一个 状态管理库 import { createPinia } from 'pinia' const pinia = createPinia() createApp(App) .use(pinia) .mount('#app')在导入
pinia后 就能在vue操作台看到:
这个像凤梨的就是
(小 tips: 代码中的 “// vue 全家桶的最后一个 状态管理库” 这句话是不是很形象? pinia 就是 vue 全家桶的最后一个拼图啦!)
-
创建 Store:
这就要用到 Pinia 的
defineStore函数了!它可以帮你定义一个 Store,并管理其中的状态数据。比如,你可以创建一个管理用户信息的 Store,或者像你笔记中那样,创建一个管理 counter 数据的 Store。// store/counter.js import { defineStore } from 'pinia' import { ref } from 'vue' export const useCounterStore = defineStore('counter', () => { const count = ref(0) function increment() { count.value++ } return { count, increment } }) // store/user.js import { defineStore } from "pinia"; import { ref, reactive, } from "vue"; // hooks 编程 export const useUserStore = defineStore("user", () => { const islogin = ref(false); const tologin = () => { islogin.value = true; } const tologout = () => { islogin.value = false; } const userInfo = reactive({ name: "", avatar: "", message: 0, uid: null, }) const setUserInfo = () => { userInfo.name = "answerball"; userInfo.avatar = "https://p26-passport.byteacctimg.com/img/user-avatar/807eceeb2975bbf82253b9da41735cfe~140x140.awebp", userInfo.message = 10, userInfo.uid = 209320781557531 } return { islogin, tologin, tologout, userInfo, setUserInfo } })敲黑板!划重点!
defineStore接收两个参数:第一个是 store 的唯一 ID,第二个是函数,用来定义 store 的状态、方法等。这个函数可以返回ref创建的响应式数据,也可以返回reactive创建的响应式对象。(小 tips: 你的笔记里也提到了 “
// 中央 状态管理 login userInfo // count 收归中央所有” 这就是 Pinia 的核心思想——把数据放到“中央”统一管理,让组件们都来这里“取用”!)
在组件中使用 Store:像呼吸一样自然!💨
有了 Store,在组件中使用就非常简单了!
-
引入 Store:
import { useCounterStore } from '../store/counter' import { useUserStore } from './store/user' -
获取 Store 实例:
const counterStore = useCounterStore() const userStore = useUserStore() -
使用 Store 中的数据和方法:
<template> <div> <h2>CompA</h2> <p>count: {{counterStore.count}}</p> <button @click="counterStore.increment">Add</button> </div> </template> <template> <div> <div v-if="islogin"> <img :src="userInfo.avatar"> </div> <div v-else> <button @click="login">登入</button> </div> <compA /> <compB /> </div> </template> <script setup> //import {ref} from 'vue' import CompA from './components/CompA.vue' import CompB from './components/CompB.vue' import { useUserStore } from './store/user' import { toRefs } from 'vue' const userStore = useUserStore() const { islogin,userInfo } = toRefs(userStore) const {tologin,tologout,setUserInfo} = userStore const login= () => { tologin(); setUserInfo(); } </script>(小 tips: 你在
App.vue中使用了toRefs将userStore中的islogin和userInfo转换为响应式对象,这能确保当 store 中的数据发生变化时,组件视图也会同步更新。 你在CompSubA.vue中使用了toRef,是为了解决响应式丢失问题,保证子组件能正确响应父组件的 count 值。)就像呼吸一样自然,有木有? 😎
Pinia 的优势:我来总结一下!💯
- 简单易学: API 非常简洁,上手快!
- 类型安全: TypeScript 支持很好,代码更健壮!
- 性能优秀: 比 Vuex 更轻量,性能更高!
- Devtools 支持: 方便调试,轻松追踪状态变化!
总结:Pinia,真香!😋
Pinia 确实是一个非常强大的状态管理工具,它可以帮我们优雅地解决组件之间的状态共享问题,让我们的代码更清晰、更易维护。如果你也还在被 Vue 的状态管理问题困扰,不妨试试 Pinia 吧!相信我,你会爱上它的!💖
最后,希望这篇文章能帮助大家更好地理解 Pinia。如果你有任何问题或者建议,欢迎在评论区留言哦!咱们下期再见!👋