首页 / 知识库 / 前端体系化快速进阶

第八章:Pinia — 状态管理

上一章解决了”页面切换”,这一章解决”数据共享”:当很多组件都要用同一份数据时,怎么办?


8.1 一个痛点:数据在组件间传得太累

回忆入门篇:父组件通过 props 把数据传给子组件。这在简单场景没问题,但项目一大就崩了。

设想一个场景:用户登录信息(用户名、头像),需要在这些地方用到:

  • 顶部导航栏(显示头像)
  • 个人中心页(显示用户名)
  • 聊天页(发消息时带上用户名)
  • ……

如果靠 props 一层层传,会变成这样的噩梦:

App
 └─ 传给 → 布局组件
       └─ 传给 → 导航栏
             └─ 传给 → 用户菜单
                   └─ 终于用上了头像

明明只是导航栏最里层要用一下头像,却要中间每一层都”帮忙传递”一遍。这叫 “props 逐层透传”,又累又难维护。

Pinia 就是来终结这种痛苦的。


8.2 Pinia 是什么

一句话:

Pinia 是一个”全局数据仓库”,任何组件都能直接从里面取数据、改数据,不用再一层层传。

把它想象成项目里的一个公共储物柜

  • 登录后,把用户信息存进储物柜
  • 导航栏要头像?直接去储物柜拿
  • 聊天页要用户名?也直接去拿

谁都能直接访问,不用互相传递。这就是”状态管理”(“状态”就是”数据”的另一种说法)。

Pinia 是 Vue 官方推荐的状态管理库,取代了老的 Vuex,更简单。


8.3 核心三件套

一个 Pinia 仓库(叫 store)由三部分组成,其实和 Vue 组件的思路很像:

名称作用类比
state存放数据组件里的 ref 数据
getters基于数据的计算组件里的计算属性
actions修改数据的方法组件里的函数

8.4 一个最小示例

第一步:安装并启用

npm install pinia

main.js 里启用:

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

createApp(App).use(createPinia()).mount('#app')

第二步:定义一个 store

新建 src/stores/user.js

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  // state:存数据
  state: () => ({
    name: '游客',
    isLogin: false
  }),

  // getters:基于数据的计算
  getters: {
    welcomeText: (state) => `你好,${state.name}`
  },

  // actions:修改数据的方法
  actions: {
    login(name) {
      this.name = name
      this.isLogin = true
    },
    logout() {
      this.name = '游客'
      this.isLogin = false
    }
  }
})

第三步:在任意组件里使用

A 组件(比如登录页)里改数据:

<script setup>
import { useUserStore } from '../stores/user'

const userStore = useUserStore()

function handleLogin() {
  userStore.login('小明')   // 调用 action 修改仓库数据
}
</script>

<template>
  <button @click="handleLogin">登录</button>
</template>

B 组件(比如导航栏)里读同一份数据,完全不需要 A 传给它

<script setup>
import { useUserStore } from '../stores/user'

const userStore = useUserStore()
</script>

<template>
  <div>{{ userStore.welcomeText }}</div>
  <!-- A 组件点了登录后,这里会自动变成 "你好,小明" -->
</template>

关键点:A 组件登录改了仓库里的 name,B 组件显示的内容会自动更新——因为它们读的是同一个仓库。数据驱动的威力,跨组件也成立。


8.5 什么时候才需要它

⚠️ 重要提醒:不要为了用而用。

  • 小项目 / 简单页面:父子传 props 就够了,别急着上 Pinia
  • 需要跨很多组件共享数据时(登录信息、购物车、全局主题设置……):才用 Pinia

判断标准:当你发现”某个数据要靠 props 传好几层”,或者”好几个不相干的组件都要用同一份数据”,就是该上 Pinia 的信号。


8.6 小结

  • 痛点:数据靠 props 逐层透传,组件一多就成噩梦
  • Pinia = 全局数据仓库(公共储物柜),任何组件直接存取,无需层层传递
  • 核心三件套:
    • state(存数据)
    • getters(算数据,类似计算属性)
    • actions(改数据的方法)
  • 用法:npm install piniamain.js 启用 → defineStore 定义 → 组件里 useXxxStore()
  • 一处修改,所有用到的组件自动更新
  • 够用就好:小项目别硬上,跨组件共享多了再用

下一章:页面有了、数据能共享了,但数据得从后端回来才行 —— 网络请求神器 Axios。