背景
@tanstack/vue-query实在是一个现代和先进的工具,自从体验了@tanstack/vue-query之后,才发现原来发请求、管理缓存和重试也能如此方便和丝滑。
而众所周知,uni-app 环境不是正常的 Web 环境,没有常规的 BOM 对象,因此要想让@tanstack/vue-query这样的为标准 Web 环境设计的库运行起来,需要一些适配和技巧。
幸运的是,ModyQyW 老师已经为我们探索过在 uni-app 环境使用@tanstack/vue-query的常见适配事项了:在 uni-app 里使用 @tanstack/vue-query,感谢这篇文章,我很顺利地在项目里用上了甜美的 vue-query。建议想要在 uni-app 里尝试 vue-query 的朋友,如果还没读过这篇文章的话,可以按照这篇文章先适配一下。
不过,在实践中,我们团队还是发现了一些问题:useQuery的refetchInterval参数在 App 和微信小程序上不生效。因此,我花了一些时间研究了一下,得出了有效的解决方案。
先说结论
如果你也遇到了这个问题,并且从搜索引擎搜到了这里,那么我可以先说答案:@tanstack/vue-query会误把 uni-app 误判为服务器环境(非浏览器环境),从而跳过定时的 refetch。
解决方法很简单也很无奈:打 patch。如果你正在使用 pnpm,可以直接使用pnpm patch命令;如果不是的话,可以把@tanstack/vue-query的 npm 包下载到本地,修改后添加本地依赖。
patch 的方式:全局搜索#updateStaleTimeout和#updateRefetchInterval两个函数,去掉if(...){return;}的判断条件中的isServer。
注意:读者应当使用编辑器的 “在所有文件中搜索功能” 来搜索所有需要修改的地方,因为这个包里除了 /src 目录下的源码外,实际被引入的是 /build 目录下的编译产物,而且这些产物还有 cjs 和 mjs 两种风格。
分析问题
定位这个问题并不难。我们检索@tanstack/vue-query中所有使用到setInterval的地方,可以很快找到queryObserver.ts文件的updateRefetchInterval函数;而我们在编译产物内直接加入console.log,就可以发现isServer的值是true,命中 return 分支,导致该库没有正常setInterval。下面是我所说关键函数的源码截图,感兴趣的读者可以看看:
而这个isServer为什么是true?其实也没啥好奇怪的:
我们的 uni-app 在 App 和 小程序环境本来就没有 window 对象,当然 100% 为true了。
解决问题
结论上面讲过了;我们需要打 patch。
当然,在 patch 的方案上,我们也有更好的方案:把 isServer 的定义直接改成 false,然后全局搜索 isServer && window.,把window.改成window?.(改成可选链)。截至我写这篇博客的时候,这样的修改是 100% 安全的;未来的读者如果不放心,也可以自行前往源码仓库搜索 + 确认。
另外的坑?
既然都打 patch 了,我们可以继续完善一下另一个兼容性的问题:在 iOS 12.2 以下的设备(如果你不需要兼容 iOS 12 的话,后面的可以不看了),按照 ModyQyW 老师的博客里的方法,为AbortController打的 polyfill 其实是不能生效的,因为这些版本的系统还没有globalThis对象。
解决方法很简单,也是打 patch,思路就是下图这样:
这篇文章就先到这里了,第一次在掘金发文章,后面有空继续分享我在做 uni-app 的项目的时候,为依赖打的各种奇奇怪怪的 patch。