前端文艺复兴:Vue3真的需要Pinia吗?

前言

说起Pinia,熟悉 vue3 开发的程序员肯定不会陌生,甚至被vue官方推荐取代vuex,成为vue全家桶之一。

疑惑

还记得之前用 vuex 时,更改 state 还分同步和异步(这里有尤雨溪的回答www.zhihu.com/question/48… ,面试还被问过为什么…,当时也是不太理解,觉得肯定有他的道理,谁知看了pinia后,更改 state 同步异步都可以…

回到正题:但我们真的需要Pinia/Vuex吗?Pinia/Vuex解决了什么问题?没有Pinia/Vuex前我们是怎么做的呢,会有什么问题?

刨根

对于以上问题,以下是本人的一些思考(有不足之处,还望赐教 🙏)

为什么需要Pinia,它解决了什么问题?先查下官网/别人怎么说;

网上很多是说,Pinia 是 Vue.js 的轻量级状态管理库

官方文档如下描述:

image.png

对于以上支撑观点,下面一个个来看,看下 Pinia 是否是必须的:

1. Pinia 是 Vue.js 的轻量级状态管理库

详阅 vue 官网关于状态管理 的文章,里面提到一个场景:多个组件共享一个共同的状态时,用 vue 原生的能力实现有点麻烦,文章推荐以下方法,将公用的数据提取到全局,这样需要的组件可以直接引用:

// store.js
import { reactive } from "vue";

export const store = reactive({
  count: 0,
  // ...
});
<!-- ComponentA.vue -->
<script setup>
import { store } from './store.js'
</script>

<template>From A: {{ store.count }}</template>
<!-- ComponentB.vue -->
<script setup>
import { store } from './store.js'
</script>

<template>From B: {{ store.count }}</template>

那我们先用这个简单的方法解决状态管理的问题,后面看下会遇到什么问题;

2. Devtools 支持(…)

不好意思,本人开发过好几个 vue 项目,从来没用过 vue devtools,都是 console.log 一把梭,目前感觉可以满足调试需要,这个在我这里就先跳过了,忽略!(用 vue devtools 很爽的可以评论分享下使用场景&经验,跪求 🙏)

3. 热更新(不必重载页面即可修改 Store、开发时可保持当前的 State)

呃…,没看太懂这个场景,如果说是下面这种热更新,上面的简单方法也可以做到,而且严格上说这应该是构建工具提供的能力吧,像 webpack hmr/vite hmr;

test.gif

既然简单的方法也可以做到我理解的热更新,平时好像也没有这方面的困扰,先跳过,忽略!(有这方面需要的请分享下经验,跪求 🙏)

4. 插件:可通过插件扩展 Pinia 功能

这个等需要用 Pinia 再考虑这个,先跳过,忽略!

5. 为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能

呃呃,上面的简单方法也可以做到,而且 ts 声明更方便,如下:

// store.ts
import { reactive } from "vue";

interface IStore {
  count: number;
  // ...
}
export const store = reactive<IStore>({
  count: 0,
  // ...
});

有了 ts 声明后,自动补全 是编辑器提供的功能。先跳过,忽略!

6. 支持服务端渲染

简单方案

先说上面简单的方法,用该方法会导致跨请求状态污染 问题;如下图,从技术上讲,我们可以在每个请求上重新初始化 store,

image.png

对于上图的 初始化 JavaScript 模块的成本可能很高 说法,我有点怀疑,因为 onMounted  或者  onUpdated  这样的生命周期钩子不会在 SSR 期间被调用,而通常让 store 变大变复杂的更改是在 onMounted 里获取数据接口回调里执行的,默认 store 就是一堆初始化的数据声明而已吧,所以在 SSR 里,为了解决 跨请求状态污染 问题,在每个请求上重新初始化 store 成本我感觉不高(个人观点,还望指教 🙏),适配 ssr 修改如下:

// store.js
import { reactive } from "vue";

export let store = createStore();
export const createStore = ()=>{
  return reactive({
    count: 0,
    // ...
  });
}
// app.js (在服务端和客户端间共享)
import { createSSRApp } from 'vue'
import { createStore, store } from './store.js'

// 每次请求时调用
export function createApp() {
  // 对每个请求都重新初始化 store 实例
  store = createStore();

  const app = createSSRApp(/* ... */)
  return { app }
}

Pinia 方案

pinia.vuejs.org/zh/ssr/

经过对比,简单方法个人认为也可以支持服务端渲染,且没有额外的概念、学习成本!

结论

据以上分析,我发现并没有必须用 Pinia 的理由,虽然其中第一点和第六点在实战中可能会需要,但用简单方法也可以解决且没有很麻烦。所以,如果为了解决这两个问题而引入一堆概念、用法,从而增大心智负担/学习成本,我觉得性价比不高,且容易居高而忘了事情本质,糊里糊涂地跟着用而已,殊不知有更简单直接的方法!全部代码如下:

只需要状态管理

// store.js
import { reactive } from "vue";

export const store = reactive({
  count: 0,
  // ...
});

需要支持服务端渲染

// store.js
import { reactive } from "vue";

export let store = createStore();
export const createStore = ()=>{
  return reactive({
    count: 0,
    // ...
  });
}
// app.js (在服务端和客户端间共享)
import { createSSRApp } from 'vue'
import { createStore, store } from './store.js'

// 每次请求时调用
export function createApp() {
  // 对每个请求都重新初始化 store 实例
  store = createStore();

  const app = createSSRApp(/* ... */)
  return { app }
}

其他

简单方法不好维护

有人拿出官方文档说上面简单的方法从长远来看不好维护。

image.png

长远来看应该是数据量变多会导致不好维护吧,但随着数据量增多,我们把 store 分模块不就行了,对于每个独立小模块,还是一如开始,例如:

// store.js
import { reactive } from "vue";

export const store = reactive({
  moduleA: {
    count: 0,
    // ...
  },
  moduleB: {
    count: 0,
    // ...
  },
  // ...
});

// 或者直接铺平
export const moduleAStore = reactive({
  count: 0,
  // ...
});
export const moduleBStore = reactive({
  count: 0,
  // ...
});

// 或者分文件模块
// ...

本人很反感那种没有事实依据的论点,有点 专家说 那味;我更推崇的是一步步深入,用事实说话,举例说明‘在 xx 情况下,你看很难维护了吧’,这会令我信服且更加理解。

刷新页面 store 数据丢失

按我理解,这只是一个现象,重要的是会造成什么问题。网上很多文章只根据现象就开始提解决方法了,比如把整个 store 缓存到 sessionStorage 里,或者 vuex/pinia 直接提供了持久化的插件。但我总感觉没触到事情本质,于是搜一下具体的场景:

    1. 有人说登录状态信息,刷新后需要保持登录状态
    1. 找不到其他场景了…(有补充的朋友请以案例说明,跪求 🙏)

那针对以上场景,简单来做不是哪个需要缓存就缓存哪个吗,比如登录信息需要缓存:

import { store } from './store.js'

// ...
window.onbeforeunload = () => {
  // 用localStorage/sessionStorage/cookie/indexDB 根据自己需要判断
  localStorage.setItem("__loginInfo__", JSON.stringify(store.loginInfo));
}
// main.js
import { store } from './store.js'

// ...
const loginInfo = localStorage.getItem("__loginInfo__");
if (loginInfo) {
  store.loginInfo = JSON.parse(loginInfo);
}
// ...

所以,我理解这种持久化问题和状态管理不应该放在一起讨论,我建议是根据场景,按需缓存

最后

纸上得来终觉浅,绝知此事要躬行

很多时候感觉在前端学不动了,其中原因之一必有:概念太多、轮子太多、技术更新太快,需要不断学习…

但个人感觉很多概念都是莫须有的,利用原生知识亦可解决,而无需增加心智负担,但要识别这些信息谈何容易啊,希望我们始终保留对问题本质的好奇吧。最后分享一句很喜欢的编程哲学语句:

Keep it simple, stupid (KISS)

2023.12.6 更新

一一看了大家的评论,下面列下我认同的文中简单方案的缺点:

  1. 如果有多处改变了store.xx,想要查找特定一次 store.xx 在哪里变更会比较麻烦;如果用pinia的话,改变 store.xx 有统一的入口,这时在入口处打个断点,根据调用盏可以快速知道是哪里变更了 store.xx

最后

欢迎关注"所谓前端"微信公众号,大家一起交流
点击扫码关注

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3是一种流行的JavaScript框架,而Pinia是一个基于Vue 3的状态管理库。Pinia提供了一种简单而强大的方式来管理应用程序的状态。下面是使用Pinia的基本步骤: 1. 安装Pinia:首先,你需要在你的Vue 3项目中安装Pinia。可以通过npm或yarn来安装Pinia。 2. 创建一个Store:在使用Pinia之前,你需要创建一个Store。一个Store是一个包含状态和操作的容器。你可以使用`defineStore`函数来创建一个Store。 3. 定义状态和操作:在Store中,你可以定义状态和操作。状态是存储数据的地方,而操作是用于修改状态的方法。你可以使用`defineStore`函数的`state`和`actions`选项来定义状态和操作。 4. 注册Store:在你的Vue应用程序的入口文件中,你需要注册你的Store。可以使用`createPinia`函数来创建一个Pinia实例,并将其作为Vue应用程序的插件进行注册。 5. 在组件中使用Store:一旦你的Store被注册,你就可以在组件中使用它了。可以使用`useStore`函数来获取Store的实例,并在组件中访问状态和操作。 下面是一个简单的示例代码,展示了如何使用Pinia: ```javascript // main.js import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const app = createApp(App) const pinia = createPinia() app.use(pinia) app.mount('#app') // store.js import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++ }, decrement() { this.count-- } } }) // App.vue <template> <div> <p>Count: {{ counter.count }}</p> <button @click="counter.increment()">Increment</button> <button @click="counter.decrement()">Decrement</button> </div> </template> <script> import { useCounterStore } from './store' export default { setup() { const counter = useCounterStore() return { counter } } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值