我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

看清楚,本文的<Await>是大写开头,来自于ReactRouter,并不是大家所熟知的那个await关键字!虽然效果类似,但是<Await>ReactRouterDom提供的一个高阶组件。而Suspense则来自于ReactDom。本文将讲述<Await>组件如何对接defer的远程数据,如何配合Suspense组件延迟显示数据。

苏南大叔:React路由,Await如何加载defer延迟数据?配合Suspense - react-router-await-suspense
React路由,Await如何加载defer延迟数据?配合Suspense(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1

前文回顾

本文中的局部延迟加载的效果,使用的组件主要有两个:

  • 来自ReactRouterDomAwait
  • 来自ReactDomSuspense

以前的文章里面,Suspense是配合Lazy完成组件的懒加载效果的,其触发条件是【需要的时候】再加载。参考文章:

本文里面,Suspense是配合Await完成组件的延迟加载效果的,其触发条件是【数据正常返回的时候】再显示。而数据接口的请求过程,一般都是个promise的过程。ReactRouter提供了一个defer,对其进行了包装。参考文章:

如果把defer请求远程数据的过程,包装进路由数组的.loader属性里面的话,就可以使用useLoaderData()获取这个包装过的DefereredDataPromise。参考文章:

三种访问远程数据方式

把这个loadDataPromise()移动到src/helper/LoadData.js文件里面。延展出三个变种:

  • loadDataPromise()
  • loadDataAwait(),这里的await指的就是await关键字。由于驼峰命名的缘故,变成了大写。
  • loadDataDefer(),一定要看代码注释!!!这里有认知陷阱!!

/src/helper/LoadData.js:

import { defer } from "react-router-dom";
const loadDataPromise = () => {
  return new Promise((r) => {
    setTimeout(() => {
      r({ name: "苏南大叔" });
    }, 2000);
  });
};
async function loadDataAwait() {
  return await loadDataPromise();
}
function loadDataDefer() {
  let _promise = loadDataPromise(); // 不能合并简写!!必须赋值到一个变量里面。
  return defer({ _promise });       // 注意,这里的 _promise 是个key,在组件里面要再次导出的,名字必须一致...
}
export { loadDataPromise, loadDataAwait, loadDataDefer };

方案一,promise 最简单

src/Nnn.js:

import { Suspense } from "react";
import { Await } from "react-router";
import { loadDataPromise } from "./helper/LoadData";
function Nnn() {
  let _promise = loadDataPromise();
  return (
    <>
      欢迎光临,
      <Suspense fallback={<>loading</>}>
        <Await resolve={_promise}>
          {(data) => {
            return <span>{data.name}</span>;
          }}
        </Await>
      </ Suspense>
      【刷新局部显示loading】
    </>
  );
}
export default Nnn;

苏南大叔:React路由,Await如何加载defer延迟数据?配合Suspense - suspense-fallback-await-1
React路由,Await如何加载defer延迟数据?配合Suspense(图3-2)

方案二,defer 最新潮

后者代码如下:
src/routes.js:

import { loadDataDefer } from "./helper/LoadData";
import Layout from "./Layout";
import Nnn from "./Nnn";
let routes = [
  {
    path: "/",
    element: <Layout></Layout>,
    children: [
      {
        path: "n",
        element: <Nnn></Nnn>,
        loader: () => {
          return loadDataDefer();
        },
      },
    ],
  },
];
export default routes;

src/Nnn.js

import { Suspense } from "react";
import { Await, useLoaderData } from "react-router";
function Nnn() {
  let { _promise } = useLoaderData(); // 注意这里的 _promise 命名来自于 loadDataDefer() 定义内部的导出
  return (
    <>
      欢迎光临,
      <Suspense fallback={"loading"}>
        <Await resolve={_promise}>
          {(data) => {
            return <span>{data.name}</span>;
          }}
        </Await>
      </ Suspense>
      【刷新局部显示loading】
    </>
  );
}
export default Nnn;

苏南大叔:React路由,Await如何加载defer延迟数据?配合Suspense - suspense-fallback-await-2
React路由,Await如何加载defer延迟数据?配合Suspense(图3-3)

fallback

Suspensefallback属性,就是准备“加载中”信息的。不准备组件,准备个纯文字信息也是可以的。比如:

<Suspense fallback={"loading"}></ Suspense>

resolve

这里Await高阶组件的resolve属性,传递的是个promise。它决定了这个局部loading效果显示多久。本文最大的变数,就来自这个promise

<Await resolve={ _promise }></Await>

promise

这个部分,主要就是准备请求数据的接口。最终得到一个Promise,传递给Await高阶组件。这里可以使用下面的函数,模拟这个过程,也可以真实的请求一个数据接口。参考文章:

根据:三种数据接口函数,两种代码放置方法,排列组合一下,共六种方案。其中只有两种方案符合【局部延迟加载】预期。分别是:

  • 原生的loadDataPromise(),那么直接传入<Await>resolve属性。【方案一】
  • loadDataDefer()放入到路由数组的loader里面,组件里面使用useLoadData()访问导出的promise。【方案二】

题外话【lazy版延迟加载】

Suspense高阶组件的真相!暂停渲染!显示fallback的内容。直到内部包裹的类promise组件被resolve!仔细体会!
附上lazy的相关关键代码。

import { Suspense, lazy } from "react";
import { loadDataPromise } from "./helper/LoadData";
const LazyChild = lazy(
  () =>
    new Promise((resolve) => {
      loadDataPromise().then(
        (data)=>{
          resolve({ default: () => <>{data.name}</> });
        }
      )
    })
);
function Nnn() {
  return (
    <>
      欢迎光临,
      <Suspense fallback={<>加载中</>}>
        <LazyChild />
      </ Suspense>
      【刷新局部显示loading】
    </>
  );
}
export default Nnn;

结语

其它的组合里面,要不就是语法错误,要不就是全局刷新而不是局部刷新,要不就是没有返回值。总之,不符合预期。Suspense也不是非要配合Await来加载数据,配合同组的lazy也是没有任何问题的。

更多苏南大叔的react经验文章,请点击苏南大叔的博客文章:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react