React18: 如何使用Suspense 等待数据异步加载

Posted Coder小何

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React18: 如何使用Suspense 等待数据异步加载相关的知识,希望对你有一定的参考价值。

Suspense API


Suspense 主要有两大用途:
1:动态加载组件 (但这并不是一个react 18的新特性)
2: 等待数据异步加载

想要实现这两种功能,需要满足对应的条件,可以在官方文档中清楚的看到:


从文档中可以看到只有Suspense-enabled data sources才可以使用这个标签,
那么在Data fetching ,也就是等待数据异步加载的过程中,则需要对数据进行特殊的处理,现有的Relay框架,Next框架则已经支持这种格式,可以直接使用Suspense,这也是suspense 处于一个实验性阶段的原因之一,希望越来越多的框架可以支持suspense~。

将Promise 转化为 Suspense支持的数据机构

既然要使用suspense ,那么就要把数据转化为suspense支持的格式,具体我们可以通过实现一个 wrapPromise 函数来进行处理:

这个函数需要完成:

  1. 接收一个Promise 作为参数
  2. 当 promise resolve 时,返回resolve 的结果
  3. 当promise reject时, 抛出 reject 的结果
  4. 当promise 还处于pending时,抛出此时的promise对象
  5. 向外暴露一个read 方法,读取promise 的结果

接下来使用代码来实现:



function wrapPromise (promise: Promise<any>) 
     let status = 'pending';
     let result: any;

     const suspender = promise.then( (resolve) => 
        status = 'success';
        result = resolve;
     , (err) => 
        status = 'error';
        result = err
     ) 

     return 
        read() // 暴露一个read方法
            if( status === 'pending')
                throw suspender
             else if ( status === 'error')
                throw result
             else if ( status === 'success')
                return result
            
        
     

有了这个函数之后,就可以对得到的promise对象进行处理

for example:

export default function fetchData(url: string)
    const promiseData = axios.get(url).then( data => data.data)
    return wrapPromise(promiseData)

请求数据并展示在页面中

// DogShow.tsx

import React from "react"
import fetchData from "../fetchData/fetchData"

const data = fetchData('https://dog.ceo/api/breeds/image/random')

const ShowDog: React.FC = () => 
    const style = 
        height: 300,
        width : 300
    
    const dogData = data.read()
    return (
        <> 
            <img src=dogData.message style=style/>
        </>
    )


export default ShowDog
// App.tsx

function App() 
  
  return (
    <div className="App">
      <header className="App-header">
        <img src=logo className="App-logo" alt="logo" />
        <Suspense fallback=<><h1>正在加载....</h1></>>
             <ShowDog></ShowDog>
        </Suspense>
      </header>
    </div>
  );


export default App;

Suspense 强制接收一个 fallback,这里面可以是发送请求时要加载的组件

数据正在请求时:

请求完成之后则会替换成相应的结果

以上,
文中如果有任何问题欢迎大家交流与讨论~

有关suspense 其他内容可以查阅官方文档:

https://react.docschina.org/reference/react/Suspense

React中异步模块api React.lazy和React.Suspense

React.lazy

React.lazy 这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件。

然后应在 React.Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。

比如:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

React.Suspense

React.Suspense 一般用于包裹lazy组件使得组件可以“等待”某些操作结束后,再进行渲染。
通过fallback 可以指定加载指示器(loading indicator),以防其组件树中的某些子组件尚未具备渲染条件。
可以用Suspense包裹多个懒加载组件,而不必为每一懒加载组件包裹一层Suspense

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}


React.lazy 目前只支持 default exports ,一个文件中export 了多个模块,则需要创建一个中间模块,来重新导出为默认模块。这能保证 tree shaking 不会出错,并且不必引入不需要的组件。

//ManyComponent.js

export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

以上是关于React18: 如何使用Suspense 等待数据异步加载的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React.lazy 和 Suspense 中获取加载进度

React中异步模块api React.lazy和React.Suspense

React18——setState变成异步——suspence组件懒加载结合异步数的传递

React18——setState变成异步——suspence组件懒加载结合异步数的传递

React suspense 防止后备微调器闪烁

如何将从远程 API 获取的初始数据与 React.Suspense 集成?