稀土掘金技术社区 2024年12月01日
Vue3真的不需要用pinia!!!
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文作者分享了在Vue3项目中使用组合式函数进行状态管理的经验,并探讨了如何避免使用Pinia库。作者通过举例说明了如何使用组合式函数实现状态的定义、获取和修改,以及如何解决多个组件共享状态的问题。文章重点阐述了组合式函数在状态管理中的优势,例如代码简洁、易于理解和维护,以及避免引入额外库的轻量化特性。最终,作者得出结论,在很多场景下,组合式函数足以胜任Vue3的状态管理任务,无需依赖Pinia等第三方库。

🤔作者在Vue3项目中尝试抛弃Pinia,使用组合式函数进行状态管理,认为组合式函数更符合极简主义的理念,代码更简洁。

🔄作者详细解释了如何使用组合式函数定义状态、创建计算属性和定义方法,并举例说明了如何在组件中使用这些状态和方法。

🤝文章探讨了组合式函数在状态共享方面的解决方案,即通过将状态变量暴露在全局环境中,实现多个组件共享同一状态。

🔒为了避免状态被外部修改,作者建议使用`readonly`包裹返回的状态,确保状态的安全性。

💡文章总结,在大多数情况下,组合式函数足以满足Vue3项目的状态管理需求,开发者可以根据自身情况选择是否使用Pinia。

自在的小李子 2024-12-01 09:00 重庆

点击关注公众号,“技术干货” 及时达!

前言

之前使用vue3都是在公司的基建项目中,为了快速达到目的,把以前vue2的模板拿来简单改改就直接用了,所以项目中用法特别乱,比如:状态管理依旧用的vuex,各种类型定义全是any,有些代码是选项式API,有些代码是组合式API...

最近终于有时间推动一下业务项目使用vue3了。作为极简主义的我,始终奉行少即是多,既然是新场景,一切从新,从头开始写模版:

pinia使用

等等,pinia?好用吗?打开官方文档研究了下,官方优先推荐的是选项式API的写法。

调用defineStore方法,添加属性state, getters, actions等。

export const useCounterStore = defineStore('counter', {  state: () => ({ count: 0, name: 'Eduardo' }),  getters: {    doubleCount: (state) => state.count * 2,  },  actions: {    increment () {      this.count++    },  },})

使用的时候,调用useCounterStore即可。

import { useCounterStore } from '@/stores/counter'import { computed } from 'vue'
const store = useCounterStore()setTimeout(() => { store.increment()}, 1000)const doubleValue = computed(() => store.doubleCount)

看上去还不错,但是我模版中全部用的是组合式写法,肯定要用组合式API,试着写了个demoref就是选项式写法中的statecomputed就是选项式中的gettersfunction就是actions

// useTime.tsimport { defineStore } from 'pinia'import { computed, ref } from 'vue'import vueConfig from '../../../common/config/vueConfig'import * as dayjs from 'dayjs'
export default defineStore('time', () => { const $this = vueConfig() const time = ref<number>() const timeFormat = computed(() => dayjs(time.value).format('YYYY-MM-DD HH:mm:ss')) const getSystemTime = async () => { const res = await $this?.$request.post('/system/time') time.value = Number(res.timestamp) } return { timeFormat, getSystemTime }})

调用时解构赋值,就可以直接用了。

// index.vue<script setup lang="ts">import { onMounted } from 'vue'import useTime from './use/useTime'
const { timeFormat, getSystemTime } = useTime()onMounted(async () => { // 请求 await getSystemTime() console.log('当前时间:', timeFormat)})</script>

优雅了很多,之前用vuex时还有个问题,storeA中的state、actions等,会在storeB中使用,这一点pinia文档也有说明,直接在storeB调用就好了,比如我想在另一个组件中调用上文中提到的timeFormat

defineStore('count', () => {  const count = ref<number>(0)  const { timeFormat } = useTime()  return {    count,    timeFormat,  }})

怎么看着这么眼熟呢,这不就是组合式函数吗?为什么我要用defineStore再包一层呢?试一试不用pinia,看能不能完成状态管理。

组合式函数

直接添加一个useCount.ts文件,申明一个组合式函数。

// useCount.tsimport { computed, ref } from 'vue'
const useCount = () => { const count = ref<number>(0) const doubleCount = computed(() => { return count.value * 2 }) const setCount = (v: number) => { count.value = v } return { count, doubleCount, setCount, }}export default useCount

使用时直接解构申明,并使用。

import useCount from './use/useCount'
const { count, setCount } = useCount()onMounted(async () => { console.log('count', count.value) // 0 setCount(10) console.log('count', count.value) // 10 })

最大的问题来了,如何在多个地方共用count的值呢,这也是store最大的好处,了解javascript函数机制的我们知道useCount本身是一个闭包,每次调用,里面的ref就会重新生成。count就会重置。

import useCount from './use/useCount'
const { count, setCount } = useCount()const { doubleCount } = useCount()
onMounted(async () => { console.log('count', count.value, doubleCount.value) // 0 0 setCount(10) console.log('count', count.value, doubleCount.value) // 10 0 })

这个时候doubleCount用的并不是第一个useCount中的count,而是第二个重新生成的,所以setCount并不会引起doubleCount的变化。

怎么办呢?简单,我们只需要把count的声明暴露在全局环境中,这样在import时就会申明了,调用函数时不会被重置。

import { computed, ref } from 'vue'
const count = ref<number>(0)const useCount = () => { const doubleCount = computed(() => { return count.value * 2 }) const setCount = (v: number) => { count.value = v } return { count, doubleCount, setCount, }}export default useCount

当我们多次调用时,发现可以共享了。

import useCount from './use/useCount'
const { count, setCount } = useCount()const { doubleCount } = useCount()
onMounted(async () => { console.log('count', count.value, doubleCount.value) // 0 0 setCount(10) console.log('count', count.value, doubleCount.value) // 10 20 })

但是这个时候count是比较危险的,store应该可以保护state不被外部所修改,很简单,我们只需要用readonly包裹一下返回的值即可。

import { computed, readonly, ref } from 'vue'
const count = ref<number>(0)const useCount = () => { const doubleCount = computed(() => { return count.value * 2 }) const setCount = (v: number) => { count.value = v } return { // readonly可以确保引用对象不会被修改 count: readonly(count), doubleCount, setCount, }}export default useCount

总结

经过我的努力,vue3又减少了一个库的使用,我就说不需要用pinia,不过放弃pinia也就意味着放弃了它自带的一些方法store.$statestore.$patch等等,这些方法实现很简单,很轻松就可以手写出来,如果你是这些方法的重度用户,保留pinia也没问题,如果你也想代码更加精简,赶紧尝试下组合式函数吧。

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Vue3 状态管理 组合式函数 Pinia 极简主义
相关文章