告别 Props 地狱!Pinia:Vue 状态管理的“大救星”来了!🌟

1,661 阅读5分钟

引言

700.gif

哈喽,各位小伙伴!👋 作为一名大三的“资深”前端小白,最近我可是被 Vue 的状态管理搞得焦头烂额。父子组件传值?兄弟组件通信?简直是把人绕进了一个“props 地狱”!🤯 就在我快要放弃的时候,Pinia 这个“大救星”出现了!😎 今天就来和大家聊聊这个拯救我于水火之中的状态管理库——Pinia!

今天我们的实验结果如图:

image.png

这种组件套组件的前端架子,按照我们曾经的经验就是,一直疯狂地propsemit,这样我们写出来的就是屎山代码。

为什么我们需要 Pinia?🤔

首先,我们来回顾一下,在没有 Pinia 的日子里,我们是怎么处理组件之间共享状态的?

  1. 父传子,子传父:  就像小时候玩“传话筒”游戏,数据一层一层地传递,稍微多几个组件就乱成一锅粥,谁都不知道数据最终跑到哪里去了。而且子组件还只能“老老实实”地接收父组件传来的 props 数据,想改?没门儿!🙅‍♀️
  2. 兄弟组件通信:  这更头疼!要先传给父组件,再由父组件传给另一个兄弟组件,中间人都要累趴下! 😫

所以,当组件层级复杂,需要共享的数据越来越多时,这种方式简直就是一场灾难!💔

(小 tips:正如代码中的注释: “<!-- <CompA :count="count" @add="increment"/> -->” 这种传统的父子传值方式,当组件嵌套较深时,会变得非常繁琐,维护起来也很痛苦。所以,我们需要一个更优雅的解决方案!)

Pinia:状态管理界的“共享单车”!🚴‍♀️

Pinia 的出现,就是来解决这个问题的!它就像共享单车,把状态数据集中管理起来,让各个组件都能随时取用,还能随时修改,简直不要太方便!🥳

Pinia 的核心思想:集中式状态管理!

Pinia 的核心在于 Store(仓库) 。你可以把 Store 想象成一个存放你所有共享状态数据的仓库。这个仓库里的数据,就像共享单车一样,每个组件都可以随时来“借用”和“归还”。

Pinia 上手:三步搞定!🚶‍♂️🚶‍♀️🚶

Pinia 用起来超级简单,只需三步:

  1. 安装 Pinia:

    npm install pinia
    
  2. 创建 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操作台看到:

image.png

这个像凤梨的就是

(小 tips: 代码中的 “// vue 全家桶的最后一个 状态管理库” 这句话是不是很形象? pinia 就是 vue 全家桶的最后一个拼图啦!)

  1. 创建 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,在组件中使用就非常简单了!

  1. 引入 Store:

    import { useCounterStore } from '../store/counter'
    import { useUserStore } from './store/user'
    
  2. 获取 Store 实例:

    const counterStore = useCounterStore()
    const userStore = useUserStore()
    
  3. 使用 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。如果你有任何问题或者建议,欢迎在评论区留言哦!咱们下期再见!👋

20200229174423_bzukt.jpg