本文会把 组合式函数(use) 叫做hook,只是一种叫法
在我们开发项目的过程中,不可避免的会写一些hook,复用一定的逻辑,使我们的业务代码看起来结构逻辑更加清晰。当然有一部分是业务hook,相当于把一部分业务功能逻辑抽到一个单独的文件,减少了.vue文件的体积。
参数变成异步的了
通常来说,我们使用hook,都是在setup的顶层,一般不大会在条件语句或者生命周期中使用。react中是肯定要用在顶层的,但是vue中没这要求。所以之前写的这个hook也不例外。
某一天,需求发生了变化,传给这个hook的一个参数,需要通过接口来获取。这个hook,返回了一个ref定义的变量。响应式变量通常也是写在顶层的,否则由于作用域的限制,template中访问不到,其他想要用这个变量的方法和函数也访问不了。
正好这个hook返回的ref变量,需要在template中使用,那就用await变成同步的试试。
嗯,很好,显示不出来了!
从告警提示中可以看到,我们需要把使用了顶层await的组件,用<Suspense>包起来。
嗯,很好,没啥问题了,下班!
产品:为啥XX在页面上显示不出来了?
某天,正在为公司奉献中,突然看到群里有人@我。群里有一张测试环境的截图,我们使用<Suspense>包裹的组件,没有渲染出来。
这又是出啥幺蛾子?虽然说<Suspense>是一个实验性功能,但也没更新版本啊,咋就不行了呢?
打开devtool看到,获取hook所用参数的接口报错了。测试环境就是这么坑爹,主要是这个接口还和终端有关,你还不能保证,这个接口以后就肯定不出问题。
从文档中可以看出,如果async setup()出现了错误,那就会一直显示<template #fallback>中的内容。所以我们可以在fallback中定义出错时显示的内容。
当组件内容比较少时,可以直接定义错误内容。如果组件内容比较多,可以把只用到hook返回ref的部分,再单独抽出来一个组件,这样就容易定义错误内容了。
如果不是很好抽(由于业务需求),可以在await后面使用catch,类似const data = await getData().catch(() => {})这种。在ts中,应该会报类型错误的一些问题,这个需要处理下。
Suspense是实验性的,不用它,怎么处理
这种情况下,只能在非顶层使用hook了。
1. 把ref变量传给hook,不在hook中定义了
我们在顶层先定义一个ref变量,再把这个变量作为参数传给hook。当然,hook可能返回不止一个变量,那我们就给定义多个了。
2. 还是先定义ref变量,然后用watch监听hook返回的变量
vue的这些api,都可以在非顶层使用,比如生命周期钩子。
const result = ref<string>()
onMounted(async () => {
const { data } = await getData()
const { resultRef } = useXXX(data)
watchEffect(() => result.value = resultRef.value)
})
当然,这种写法确实感觉不伦不类,虽然vue是支持的。
最后
<Suspense>是一个比较优雅的解决方法,但它一直处于实验阶段,
我们知道,react中也有suspense,看起来不大像遇到了一些很难处理的边界情况,不知道为啥一直没有稳定下来。如果有jy知道的话,欢迎评论区告知。