React路由,数据获取相关函数defer(),await之外另一选择
发布于 作者:苏南大叔 来源:程序如此灵动~本文说的这个defer()
很有意思,它并非nodejs
原生的,它来自于ReactRouter
,并且将在下一个ReactRouter@v7
里面被废除。目前的ReactRouter@v6
版本里面,它还是能够使用的。它惊艳到苏南大叔的地方在于:它打破了async
+await
的固定组合,提供了一个新的通过promise
获取数据的可能性。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
。本文的defer
是个包装函数,并非原生自带,来自于ReactRouter
,并且即将被ReactRouter@v7
废弃。
哪个defer?
以前苏南大叔写过一个script
标签的defer
属性。本文的defer()
和这个defer
属性是没有半毛钱关系的。纯属巧合。前文链接:
本文的refer
并不是nodejs
原生自带,而是由reactrouter
提供的导出函数,并且还不是更加常见的react hook
。并且,极有可能能够脱离react
路由独立使用。这,就非常非常的不react
了。
对于同一个耗时的Promise
请求,本文就存在着两种不同的写法了。分别是await
和defer
。对于react
程序来说,await
是串行,阻碍渲染。defer
是并行,并不阻碍页面渲染。
基础耗时请求
const getData = () => {
return new Promise((r) => {
setTimeout(() => {
r({ name: "苏南大叔" });
}, 3000);
});
};
经常使用setTimeout()
来模拟远程接口返回,实际的应用中,确是经常使用axios
来做这个请求的。参考文章:
const getData = () => {
return new Promise((r) => {
const axios = require('axios');
axios.get("http://127.0.0.1:3222/hello").then(res => {
r(res.data);
})
.catch(err => {
// reject();
});
});
};
写法一,async + await
对于promise
来说,一直无法脱离async
和await
的影子。有的时候,会为了一些写法,硬生生的在函数定义前面加上个async
字样,很令人无语。
当然,本文中的await
就是原生的await
,并不是react router
里面的<Await>
。
参考代码:
const r1 = getData();
r1.then((a) => {
console.log(a, "then");
});
const r2 = await getData(); // 有条件执行
console.log(r2, "await");
(async () => {
const r3 = await getData();
console.log(r3, "async + await");
})();
写法二,本文主角defer
参考测试代码:
import { defer } from "react-router-dom";
const ppp = getData();
const rrr = defer({ ppp });
这里的ppp
变量是个promise
,而rrr
是个自定义的DeferredData
类型。
单独使用defer
的时候,肯定是可以独立运行的,并不需要任何react router
的定义。由于没有相关文档,最好的解析返回值数据的方法,目前并不知晓。但是,可以在适当的时候(比如:promise
成功后),通过下面的方式获得数据。
rrr.unwrappedData.ppp
这个地方,测试结果和时间的掌控关系密切。在promise
结果返回之前,console.log
里面输出的DeferredData
对象的.unwrappedData
属性,点开是个错误信息提示。而promise
结果返回之后,点开的话,是个正常显示的数据。难道这个.unwrappedData
属性,是个未决的属性?
当然,react router
里面,并不是通过上述方法,获得返回值的。具体的获得方式,待后续文章讨论。
可能遇到的问题
测试过程,也是较多波折的。出于前后文章延续测试的目的,本文的代码,是完全替换了cra
模版的src/index.js
文件。
普通的await
版本测试,因为代码里面有直接写的await
(不带async
)。直接放在index.js
里面,npm start
的话,会得到错误提示:
Module parse failed: Top-level-await is only supported in EcmaScript Modules
那么node index.js
的话,会得到提示:
SyntaxError: await is only valid in async functions and the top level bodies of modules
那么,解决方案有两个。
- 一个是联合后续的
defer
测试,在顶部添加import
字样。那么,就可以直接npm start
看结果了。【纯属歪打正着】 - 或者,修改
index.js
文件名为index.mjs
。然后node index.mjs
,就可以单独测试async+await
的结果了。
结语
这个defer()
的写法,打破了async
+await
的万年垄断。苏南大叔翻了翻代码,好像实现上有个.subscribe()
方法。使用这个订阅方法的各种环境中,都是有一种非常轻松的氛围的。比如socket
或者redis
。
更多react
的经验文章,请参考苏南大叔的博客:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。