咱们都曾遭逢过这样的烦恼:漫长的加载界面之后,却只等来了毫无反响的网页。随处可见的加载图标不停旋转,但一切仿佛都停滞不前。让我为你描述一个更生动的画面:
这种状况通常出现的要素是,网站试图在你一落地页面就 一切必要的数据。或许是正在处置某个API恳求,或许多个API在顺序 数据,造成页面加载提早。
。你或许会想:"这么大的公司怎样会不 用户体验?真是令人绝望。"因此,用户往往会选用分开网站,这不只影响了
这些重量级页面的数据,让用户一进入页面就能立刻与之交互,会怎样呢?
refetching)概念的由来,也正是咱们在这篇博文中将深化讨论的内容。
目录
预取技术:处置方案
针对上述疑问,咱们的目的是在页面加载至网站之前,就 该页面所需的数据,如此一来,用户在页面加载时便无需再次 数据。这种技术被称作预取。从技术层面来讲,其定义如下:
所需数据的方法,使关键组件无需期待数据即可加载,从而优化用户体验。
这可以改善用户体验,增强客户对你网站的信
愈加以用户为核心。要实施预取,咱们须要了解用户在网站上的行为。例如,最常访问的页面,或哪些组件在小交互(如悬停)时
运行预取技术。但是,作为开发人员,咱们应该审慎经常使用这个概念。适度预取也或许降低网站速度,由于你试图为未来场景 少量数据,这或许会阻塞主页面的数据
预取技术如何优化用户体验
让咱们来看几个预取技术有益的场景:
这些都是在运行中成功预取的方法,它们有助于优化用户体验。
在本文中,咱们将讨论最后一个场景:" "。这是一个预取技术能够带来 清楚好处,为用户提供更流利体验的典型
疑问剖析
让我为你具体论述这个疑问。请想象以下场景:
如今,想象用户将鼠标悬停在该元素上,随后期待数据被预取并显示在弹出窗口中。在这段期待的期间里,用户会看到一个骨架加载器(Skeleton Loader)。
这个场景大抵如下(此为动图,须要下载anigif.ocx控件观看):
每当用户将鼠标悬停在图片上时,他们必定期待很长期间,这真的很令人丧气: (此为动图,须要下载anigif.ocx控件观看)
要处置此疑问,有两种处置方案可供你参考,以协助你着手并依据自身需求优化处置方案。
处置方案一:在父组件中预取数据
这个处置方案准许你在弹出窗口出现之前便已预取数据,而非在组件加载时预取。
当鼠标悬停在某个元素(如图片)上时,弹出窗口会浮现。咱们能够在这个元素的父组件上成功鼠标进入时预取数据。鉴于此,在实践须要悬停显示的组件(如图片)之前,咱们就曾经预备好弹出窗口所需的数据,并将这些数据传递给弹出窗口组件。
这种处置方案并不能齐全消弭加载形态,不过它能够清楚降低用户看到加载形态的概率。(此为动图,须要下载anigif.ocx控件观看)
处置方案二:页面加载时预取数据
这个处置方案遭到了相似x.com(或许是指Facebook的前身或相似的大型网站)的数据加载战略的启示,即在弹出窗口组件中,它们在主页面加载时局部预取数据,并在组件挂载时预取残余的数据。(此为动图,须要下载anigif.ocx控件观看)
正如你从下面的灵活图中所看到的,用户的团体资料具体消息在弹出窗口中检查。细心观察,你会发现与关注者关系的具体消息是稍后预取的。
当你须要在弹出窗口中显示少量数据,但一次性性预取一切数据或许对弹出窗口挂载或主页面加载形成较大累赘时,采取这种技术就显得十分高效。
一个更好的处置方案是,在主页面上局部加载所需的数据,并在组件挂载时加载残余的数据。
在这个例子中,咱们在鼠标进入图片的父元素时预取了弹出窗口的数据。如今想象一下,一旦弹出窗口的数据加载成功,你还须要预取额外的具体消息。因此,基于上述x.com的方法,咱们可以在弹出窗口加载时预取额外的数据。这样做的结果是:
在这里,咱们采取以下步骤:
当鼠标进入图片的父组件时,咱们预取渲染弹出窗口所必需的关键数据。
这给咱们足够的期间来预取关键数据。
在弹出窗口加载时,咱们预取另一组数据,即相册数量。当用户阅读姓名和邮箱等消息时,下一组数据曾经预备就绪,随时可以展现。
经过这种模式,咱们可以做一些小而奇妙的优化,最大限制地增加用户盯着屏幕上的加载动画发愣的期间。
React中如何成功预取
在本局部中,咱们将简明引见如何成功上述预取示例运行程序。
名目设置
要开局创立支持预取配置的运行,请依照以下步骤操作:
你可以经常使用 Vite.js(这是我经常使用的工具)或 Create React App 来创立你的运行
yarn create vite prefetch-example --template react-ts
当你用VS Code关上prefetch-example文件夹后,应该会看到如下的文件夹结构。
如今让咱们深化了解一下咱们将为这个运行构建的组件。
组件
在此示例中,咱们将经常使用3个组件:
PopoverExample 组件
让咱们从第一个组件开局,即PopoverExample。这个组件在界面上展现了一个图像头像(avatar),并在其右侧显示了一些文本。它的规划应该相似于这样:(此为动图,须要下载anigif.ocx控件观看)
该组件的目的是作为一个示例,模拟事实生存中的场景。在这个组件中,当用户将鼠标悬停在图片上时,会加载一个弹出窗口组件。
import { useState } from "react";import { useFloating, useHover, useInteractions } from "@floating-ui/react";import ContentLoader from "react-content-loader";import UserProfile from "./UserProfile";import UserProfileWithFetching from "./UserProfileWithFetching";export const MyLoader = () => ( <ContentLoader speed={2} width={340}height={84} viewBox="0 0 340 84" backgroundColor="#d1d1d1" foregroundColor="#fafafa" > <rect x="0" y="0" rx="3" ry="3" /> <rect x="76" y="0" rx="3" ry="3" /> <rect x="127" y="48" rx="3" ry="3" /> <rect x="187" y="48" rx="3" ry="3" /> <rect x="18" y="48" rx="3" ry="3" /> <rect x="0" y="71" rx="3" ry="3" /> <rect x="18" y="23" rx="3" ry="3" /> <rect x="166" y="23" rx="3" ry="3" /> </ContentLoader>);export default function PopoverExample() { const [isOpen, setIsOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); const [data, setData] = useState({});const { refs, floatingStyles, context } = useFloating({ open: isOpen, onOpenChange: setIsOpen, placement: "top", });const hover = useHover(context);const { getReferenceProps, getFloatingProps } = useInteractions([hover]);const handleMouseEnter = () => { if (Object.keys(data).length === 0) { setIsLoading(true); fetch("https://jsonplaceholder.typicode.com/users/1") .then((resp) => resp.json()) .then((data) => { setData(data); setIsLoading(false); }); } };return ( <div style={{ display: "flex", flexDirection: "row", alignItems: "center", textAlign: "left", }} onMouseEnter={handleMouseEnter} > <span style={{ padding: "1rem", }} > <img ref={refs.setReference} {...getReferenceProps()} style={{ borderRadius: "50%", }} src="https://cdn.jsdelivr.net/gh/alohe/avatars/png/vibrent_5.png" /> </span> <p> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </p> {isOpen && ( <div className="floating" ref={refs.setFloating} style={{ ...floatingStyles, backgroundColor: "white", color: "black", padding: "1rem", fontSize: "1rem", }} {...getFloatingProps()} > {isLoading ? ( <MyLoader /> ) : ( <UserProfile hasAdditionalDetails {...data} /> )} {/* <UserProfileWithFetching /> */} </div> )} </div> );}
程序运转的环节,让我逐渐解释:
UserProfile 组件
既然咱们曾经定义了 Popover 示例,那么此刻便是深化探求 UserProfile 组件细节的时刻了
这个组件出如今Popover组件外部。
为了演示预取示例,咱们必定确保UserProfile组件仅作为展现组件存在;也就是说,它外部不蕴含任何
关于这个组件的关键点是,数据的 取出当初父组件PopoverExample中。在这个组件 ,当鼠标进入该组件(即触发mouseenter事情)时,咱们开局 取数据。这是咱们之前讨论过的处置方案#1。
这为用户在将鼠标悬停在图像上之前提供了 取数据。以下是关系代码:
import { useEffect, useState } from "react";import { MyLoader } from "./PopoverExample";export default function UserProfileWithFetching() { const [isLoading, setIsLoading] = useState(false); const [data, setData] = useState<Record<string, string>>({});useEffect(() => { setIsLoading(true); fetch("https://jsonplaceholder.typicode.com/users/1") .then((resp) => resp.json()) .then((data) => { setData(data); setIsLoading(false); }); }, []);if (isLoading) return <MyLoader />;return ( <div> <div>name: {data.name}</div> <div>email: {data.email}</div> <div>phone: {data.phone}</div> <div>website: {data.website}</div> </div> );}
此运行程序的完整代码可在
适度预取也或许造成性能降低
总结
了解到成功预取可以清楚优化 的Web运行程序的速度和照应性,从而提高用户满意度。
为了进一步阅读,请参考以下文章:
原文题目: How to Boost Web Performance with Prefetching – Improve User Experience by Reducing Load Time ,作者:Keyur Paralkar