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 函数来进行处理:
这个函数需要完成:
- 接收一个Promise 作为参数
- 当 promise resolve 时,返回resolve 的结果
- 当promise reject时, 抛出 reject 的结果
- 当promise 还处于pending时,抛出此时的promise对象
- 向外暴露一个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组件懒加载结合异步数的传递