Nuxt3 useFetch和$fetch的探讨以及封装请求处理
探讨
nuxt3采用了Hydration水合这样一个概念,用于处理服务端生成静态html与客户端js脚本的结合,实现一个可动态交互的页面应用,这个过程被称之为水合。
水合的过程可能会相对复杂一些,需要考虑到脚本加载、DOM的匹配、交互的激活(事件)、状态管理等等。
其中状态的管理,我目前使用的时候,发现它并不是理想中的那种状态。
理想中可能是:
服务端渲染时发起了一个api请求,获得了用户的数据,此时我们会将其存储到状态管理中,比如pinia之类的,然后客户端获取到服务端返回的数据,然后自己将pinia的数据恢复到内存中,如果使用了持久化存储,应该会自己将其存储到local之中。
但是,实际情况是,如果你想持久化,那你就必须自己在客户端的时候手动存储,也就是说,在服务端拿到的数据,哪怕你确实在代码中写了持久化处理,也是无效的,目前最佳实践就是在onMounted
中处理pinia的数据存储。
如果想在服务端拿到状态,我们还是需要使用到cookie。
除了状态管理,最复杂的其实是请求的处理,nuxt提供了好几种请求的方法。
useAsyncData
用于在水合时包装请求体,通过参数key唯一标识,减少服务端与客户端重复请求;$fetch
用于实际发起请求的方法,类似与axios,基于ofetch库的封装;useFetch
是将useAsyncData和$fetch
封装后的方法,减少每次都手动输入key做唯一标识的麻烦步骤,效果等同于useAsyncData和$fetch
的组合;useLazyAsyncData
用于在水合时不阻断页面的加载展示,比如你有一个b页面,在b页面的setup中就发起了useFetch请求,如果请求需要10s,那么用户就需要等到10s数据获取后,b页面才会进入并展示,如果使用useLazyAsyncData配合$fetch,就会直接进入页面,等数据获取后再渲染对应的dom元素;useLazyFetch
等同于useLazyAsyncData和$fetch的组合;
虽然说useAsyncData这种,通过key可以减少重复请求,那么useFetch也是一样的,但是实际上却略有不同?
<script lang="ts" setup>
const { data, error } = await useFetch("/xxxx", {
onResponse() {
console.log(1);
}
});
</script>
当页面第一次加载的时候,服务端生成html,此时就会就会触发useFetch
,但是当客户端渲染时,也会触发一次请求,这次请求不会出现在浏览下开发者控制台Network里面,但是响应拦截器onResponse
会被触发两次,你会在控制台看到log的两次打印。
于是我去查看了服务器的日志,api请求确实只发起了一次,由此我初步判定是拦截器会被运行两次,所以大伙使用上可能需要注意下,如果在这里做计数处理,可能是不准的。
由于这种情况,可能会导致像我一样,认为首次页面的请求会触发两次,导致认为useAsyncData
根本没啥作用。
但是如果你直接使用$fetch
去请求,是真的会触发两次,一次在服务器,一次在客户端。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
全部评论 98
eeee
Google Chrome MacOSdfas
Google Chrome MacOS半壶水
Google Chrome MacOS木灵鱼儿
FireFox Windows 10