交互导入模式

303 阅读2分钟

1. 本文主题:

  1. 针对于许多场景下,使用可交互时延迟导入功能;
  2. React中lazy + Suspense方法;以及自定义实现该功能;
  3. 理解React Suspense;

2. 使用场景

⚠️: 只有在交互前无法预取资源才应该在第一代码进行交互时加载。

  1. 在可交互时导入功能代码;
  2. 在可交互时加载第三方小组件;
  3. 认证(这里我目前还没有这类需求,参考支付宝授权等等场景)
  • 应用程序可能需要通过客户端的JavaScript SDK来支持与服务的认证。这些SDK有时会很大,JS执行成本很高,如果用户不打算登录,我宁可不急于在前期加载它们。相反在用户点击 "登录 "按钮时动态导入认证库,在初始加载时保持主线程更多的空闲状态。

2.1 加载时机

  1. 当用户第一次点击与该组件进行交互时;
  2. 滚动组件到可视区域中;
  3. 将该组件推迟到浏览器空闲状态时加载(通过 requestIdleCallback)。

2.2 加载资源的方式

  1. Eager - 立即加载资源(加载脚本的正常方式)。
  2. 基于路由的延迟加载 - 当用户跳转到路由或组件时加载。
  3. 基于交互时延迟加载 - 当用户点击用户界面时加载(如显示聊天)。
  4. 在可是区域内延迟加载 - 当用户向组件滚动时加载。
  5. 预取 - 在需要之前加载,但在关键资源加载之后加载
  6. 预载 - 急切地,以更大程度的紧迫感;

3. 解决方案

  1. 先使用html和css展示一个模拟的按钮;
  2. 在用户进行功能处理时,比如点击展开框,点击认证功能键等,才拉取资源。

4. React处理方案

  1. 组件级别: 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;
  1. 拓展实现
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;