有了Composition API后,有些场景或许你不需要pinia了
前言
日常开发时有些业务场景功能很复杂,如果将所有代码都写在一个vue组件中,那个vue文件的代码量可能就几千行了,维护极其困难。这时我们就需要将其拆分为多个组件,拆完组件后就需要在不同组件间共享数据和业务逻辑。有的小伙伴会选择将数据和业务逻辑都放到
pinia
中,这样虽然可以解决问题。但是如果将所有的复杂的业务都放在
pinia
中,那么
pinia
就会变得很乱。
将数据和业务逻辑都封装到
hooks
中
这时你还有另外一个选择,使用
Composition API
将数据和业务逻辑都抽取到
hooks
中。
state
状态的定义和更新以及具体的业务逻辑全部由
hooks
内部维护,组件只负责使用
hooks
暴露出的
state
状态和方法。
下面是我们封装的
hooks
:
export const useStore = () => {
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
function increment() {
count.value = count.value + 1;
}
function decrement() {
count.value = count.value - 1;
}
return {
count,
doubleCount,
increment,
decrement,
};
};
组件只需要使用hooks中暴露出的状态
count
和
doubleCount
,以及方法
increment
和
decrement
,无需关注具体的内部逻辑是如何实现的。
上面的封装其实是有问题的,如果我们将组件拆为两个,分别为
CountValue.vue
(显示
count
的值)和
CountBtn.vue
(修改count变量值)。
CountValue.vue
组件代码如下:
<template>
<p>count的值是{{ count }}</p>
<p>doubleCount的值是{{ doubleCount }}</p>
</template>
<script setup lang="ts">
import { useStore } from "./store";
const { count, doubleCount } = useStore();
</script>
CountBtn.vue
组件代码如下:
<template>
<button @click="decrement">count--</button>
<button @click="increment">count++</button>
</template>
<script setup lang="ts">
import { useStore } from "./store";
const { decrement, increment } = useStore();
</script>
由于我们的
count
变量是在
useStore
函数中定义的,所以每调用一次
useStore
函数都会重新定义一个
count
变量。在我们这里
CountValue
和
CountBtn
组件都在
setup
中调用了
useStore
函数,通过
useStore
函数拿到的就不是同一个
count
变量。这样就会导致我们在
CountBtn
中修改了
count
变量的值,但是
CountValue
组件中显示的
count
变量的值一直没变。
多个组件同时调用
hooks
如何共享同一份state状态
要解决上面的问题其实很简单,问题的原因是因为每次调用
useStore
函数都会生成一个新的
count
变量。那我们就不将
count
变量的定义写在
useStore
函数中,只需要将
count
变量的定义写在
useStore
函数的外面就可以了。
下面是优化后的
hooks
:
import { computed, ref } from "vue";
// 将count的定义放在外面
let count;
export const useStore = () => {
if (!count) {
count = ref(0);
}
const doubleCount = computed(() => {
return count.value * 2;
});
function increment() {
count.value = count.value + 1;
}
function decrement() {
count.value = count.value - 1;
}
return {
count,
doubleCount,
increment,
decrement,
};
};
我们将
count
变量定义放在了
useStore
的外面,并且只有第一次调用
useStore
时
count
的值为空才会执行
count = ref(0)
。后面再次调用
useStore
时由于
count
已经被
ref
赋值为一个对象了,所以就不会再次走
if
逻辑。这样
CountValue
和
CountBtn
组件中调用
useStore
拿到的
count
变量都是我们在
useStore
函数外面定义的了。
那么这里的计算属性
doubleCount
为什么不放在
useStore
外面定义也可以呢?因为计算属性
doubleCount
的值是由
count
变量计算得来的,所以我们只需要保证每次调用
useStore
时访问的
count
变量是同一个,那么
doubleCount
计算属性的值就是相同的。当然你也可以将计算属性
doubleCount
的定义也放在
useStore
外面。
总结
这篇文章介绍了在多个组件中需要复用状态和业务逻辑的情况时,我们可以不将这些状态和业务逻辑写到
pinia
中,而是使用
Composition API
将状态和业务逻辑封装成一个
hooks
。为了多个组件同时调用
hooks
时能够共用同一个
state
状态,我们需要将定义的
ref
变量写在
useStore
函数外面。
如果我的文章对你有点帮助,欢迎关注公众号:【欧阳码农】,文章在公众号首发。你的支持就是我创作的最大动力,感谢感谢!