企业项目管理、ORK、研发管理与敏捷开发工具平台

网站首页 > 精选文章 正文

Vue 状态管理:从Vuex到Pinia,Vue 3官方推荐的状态管理库深度解析

wudianyun 2024-12-20 11:05:25 精选文章 17 ℃

在编程界有句老话:“命名和缓存失效是世上两大难题。” 我得说,在现代Web应用的状态管理上,这难题得排第三!

今天,咱们来深挖一下Vue的状态管理之道,并介绍一个超直观的解决方案——Pinia。

Vue状态管理:那些坑和局限性

自Vue 2起,我们用data属性来定义组件的状态,就像这样:

<template>
  <div>{{ user.name }}</div>
</template>

<script>
export default {
  data() {
    return { user: { name: 'John', age: 25 } };
  }
};
</script>

这就是所谓的 选项 API,在Vue 3中依然可用。Vue 3还带来了 组合式 API,它用reactiveref等新招数来定义状态。用这新API,我们可以这样写组件脚本:

<script setup>
import { reactive } from 'vue'

const user = reactive({ name: 'John', age: 25 });
</script>

但如果要跨组件访问状态,比如在导航栏显示用户名,在个人资料页展示详细信息,这就尴尬了。通常,我们用props逐层传递,但层级一多,就得在每个组件里加props,不管用不用得上。这叫prop 穿透,真不推荐。

更新共享数据时,子组件不能直接改props,得发事件让父组件来更新,再传下去。这...感觉有点笨。

Vue 3的救星来了:组合式 API 让我们能在任何脚本里用refreactive,还能导出状态,整个应用都能用。

我们可以把这状态叫做存储 (store)。比如,创建个store/user.js

import { reactive } from 'vue'

const user = reactive({ name: 'John', age: 25 });

export { user };

然后在组件里这么用:

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

<template>
  <h1>Hello, {{ user.name }}! You are {{ user.age }} years old.</h1>
</template>

看,现在状态有单一来源,组件间还能共享。

但这种模式虽简单,却不适合服务器端渲染 (SSR),因为状态只创建一次,可能导致数据泄露。而且,随着应用变大,可能需要更强大的状态管理。

Pinia:现代Vue应用的存储解决方案

Pinia 不仅支持SSR,还有Vue Devtools集成、热更新、TypeScript友好等优点。

Pinia由Vue Router的开发者Eduardo打造,现已取代Vuex,成为Vue 3官方推荐的状态管理库。

安装和设置

安装Pinia就一行命令:

npm install pinia

然后创建Pinia实例,传给Vue应用:

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

const pinia = createPinia()

const app = createApp(App)
app.use(pinia)
app.mount('#app')

现在,创建和管理存储就这么简单。

创建存储

defineStore方法创建Pinia存储,第一参数是名,第二参数是配置。比如,我们改写下user存储:

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({ name: 'John', age: 25 }),

  getters: {
    canVote: (state) => state.age >= 18,
  },

  actions: {
    blowCandles() {
      this.age++;
    }
  }
});

这就是选项存储 (Option Stores)。

喜欢组合式 API?Pinia也支持。用设置存储 (Setup Stores),用refcomputed定义状态和计算属性,函数返回要公开的:

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useUserStore = defineStore('user', () => {
  const name = ref('John');
  const age = ref(25);

  const canVote = computed(() => age.value >= 18);

  const blowCandles = () => age.value++;

  return { name, age, canVote, blowCandles };
});

设置存储的好处包括定义观察器、使用其他组合函数、注入属性等。

使用存储

定义了Pinia存储后,就可以在组件或组合函数里导入使用了:

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

const user = useUserStore();
</script>

<template>
  <button @click="user.blowCandles">
    I am {{ user.name }} and it's my birthday!
  </button>
</template>

通过user对象访问状态和操作,简单直观。解构时,用storeToRefs保持反应性。

真实例子

实际应用中,我们不会用固定值初始化存储。来看个登录示例:

import { ofetch } from 'ofetch'
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', () => {
  const data = ref();
  const token = ref();

  const isLoggedIn = computed(() => Boolean(token.value));

  async function login({ email, password }) {
    const { data, token: tok } = await ofetch('https://example.com/login', {
      method: 'POST',
      body: { email, password }
    });

    data.value = data;
    token.value = tok;
  }

  // ... logout, other methods
});

存储是封装应用逻辑的好地方。比如,登录操作请求API,保存用户数据和令牌。

然后在组件里这么用:

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

const user = useUserStore();
// ... form, error, handleSubmit
</script>

<template>
  <!-- ... template code -->
</template>

Pinia不仅管理用户会话,还能跟踪其他数据,减少服务器请求,让应用更快。

Pinia也适用于Vue 2

Pinia完全兼容Vue 2,所以如果你的Vue 2应用用Vuex,迁移到Pinia是升级到Vue 3的好起点。

Pinia Vue Devtools 插件

如果你用Vue Devtools,Pinia会有个新标签让你浏览存储,检查状态,甚至导入导出JSON。

总结

状态管理可能看起来有点吓人,但一旦掌握了,就简单多了。Pinia帮你组织数据,轻松访问。开发体验棒,集成简单。想试试?去官网看看。

最近发表
标签列表