1. 本文主题:
- 针对于许多场景下,使用可交互时延迟导入功能;
- React中
lazy + Suspense方法;以及自定义实现该功能; - 理解React Suspense;
2. 使用场景
⚠️: 只有在交互前无法预取资源才应该在第一代码进行交互时加载。
- 在可交互时导入功能代码;
- 在可交互时加载第三方小组件;
- 认证(这里我目前还没有这类需求,参考支付宝授权等等场景)
- 应用程序可能需要通过客户端的JavaScript SDK来支持与服务的认证。这些SDK有时会很大,JS执行成本很高,如果用户不打算登录,我宁可不急于在前期加载它们。相反在用户点击 "登录 "按钮时动态导入认证库,在初始加载时保持主线程更多的空闲状态。
2.1 加载时机
- 当用户第一次点击与该组件进行交互时;
- 滚动组件到可视区域中;
- 将该组件推迟到浏览器空闲状态时加载(通过 requestIdleCallback)。
2.2 加载资源的方式
- Eager - 立即加载资源(加载脚本的正常方式)。
- 基于路由的延迟加载 - 当用户跳转到路由或组件时加载。
- 基于交互时延迟加载 - 当用户点击用户界面时加载(如显示聊天)。
- 在可是区域内延迟加载 - 当用户向组件滚动时加载。
- 预取 - 在需要之前加载,但在关键资源加载之后加载
- 预载 - 急切地,以更大程度的紧迫感;
3. 解决方案
- 先使用html和css展示一个模拟的按钮;
- 在用户进行功能处理时,比如点击展开框,点击认证功能键等,才拉取资源。
4. React处理方案
- 组件级别:
lazy + Suspense:
- React.lazy函数: 提供了一种内置的方法,可以将应用程序中的组件分离成独立的JavaScript块;
- Suspense组件: 与lazy结合起来时,可以处理加载状态。
import React, { lazy, Suspense, useState } from "react";
// 使用react组件Suspense结合lazy,按需加载emoji组件
const LoadEmoji = lazy(() => import("emoji-picker-react"));
const Lazy = () => {
const [chosenEmoji, setChosenEmoji] = useState(false);
return (
<div>
<button onClick={() => setChosenEmoji(true)}>打开emoji</button>
{chosenEmoji && (
<Suspense fallback={<div>loading...</div>}>
<LoadEmoji />
</Suspense>
)}
</div>
);
};
export default Lazy;
- 拓展实现
import React, { Component, createElement, useState } from "react";
const CreateElementPinker = () => {
const [emojiDiv, setEmoji] = useState(null);
// 点击打开按钮时再加载
const openEmojiBtn = () => {
import("emoji-picker-react")
.then((module) => module.default)
.then((emojiPinker) => {
setEmoji(createElement(emojiPinker));
});
};
return (
<div>
<button onClick={openEmojiBtn}>打开emoji</button>
{emojiDiv ? <div>{emojiDiv}</div> : <div>loading...</div>}
</div>
);
};
export default CreateElementPinker;