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的经验文章,请参考苏南大叔的博客: