在 React 中实现图片懒加载

ReactReactBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将探索如何在 React 应用程序中实现图片懒加载。懒加载通过延迟图片加载直到需要时才进行,从而提高页面性能,减少初始加载时间并改善用户体验。我们将使用 Intersection Observer API 和 React 钩子来创建一个支持懒加载图片的可复用组件。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL react(("React")) -.-> react/FundamentalsGroup(["Fundamentals"]) react(("React")) -.-> react/AdvancedConceptsGroup(["Advanced Concepts"]) react(("React")) -.-> react/StateManagementGroup(["State Management"]) react/FundamentalsGroup -.-> react/conditional_render("Conditional Rendering") react/AdvancedConceptsGroup -.-> react/hooks("React Hooks") react/StateManagementGroup -.-> react/use_state_reducer("Using useState and useReducer") subgraph Lab Skills react/conditional_render -.-> lab-38350{{"在 React 中实现图片懒加载"}} react/hooks -.-> lab-38350{{"在 React 中实现图片懒加载"}} react/use_state_reducer -.-> lab-38350{{"在 React 中实现图片懒加载"}} end

图片懒加载

虚拟机中已提供 index.htmlscript.js。一般来说,你只需在 script.jsstyle.css 中添加代码。

要渲染支持懒加载的图片,请按以下步骤操作:

  1. 使用 useState() 钩子创建一个有状态的值,用于指示图片是否已加载。
  2. 使用 useEffect() 钩子检查 HTMLImageElement.prototype 是否包含 'loading'。这将检查是否原生支持懒加载。如果不支持,则创建一个新的 IntersectionObserver,并使用 IntersectionObserver.observer() 来观察 <img> 元素。使用钩子的返回值在组件卸载时进行清理。
  3. 使用 useCallback() 钩子来记忆 IntersectionObserver 的回调函数。此回调将更新 isLoaded 状态变量,并使用 IntersectionObserver.disconnect() 断开 IntersectionObserver 实例的连接。
  4. 使用 useRef() 钩子创建两个引用。一个将保存 <img> 元素,另一个在必要时保存 IntersectionObserver 实例。
  5. 最后,使用给定的属性渲染 <img> 元素。如有必要,应用 loading='lazy' 使其懒加载。使用 isLoaded 来确定 src 属性的值。

以下是这些步骤的示例实现:

const LazyLoadImage = ({
  alt,
  src,
  className,
  loadInitially = false,
  observerOptions = { root: null, rootMargin: "200px 0px" },
  ...props
}) => {
  const observerRef = React.useRef(null);
  const imgRef = React.useRef(null);
  const [isLoaded, setIsLoaded] = React.useState(loadInitially);

  const observerCallback = React.useCallback(
    (entries) => {
      if (entries[0].isIntersecting) {
        observerRef.current.disconnect();
        setIsLoaded(true);
      }
    },
    [observerRef]
  );

  React.useEffect(() => {
    if (loadInitially) return;

    if ("loading" in HTMLImageElement.prototype) {
      setIsLoaded(true);
      return;
    }

    observerRef.current = new IntersectionObserver(
      observerCallback,
      observerOptions
    );
    observerRef.current.observe(imgRef.current);
    return () => {
      observerRef.current.disconnect();
    };
  }, []);

  return (
    <img
      alt={alt}
      src={isLoaded ? src : ""}
      ref={imgRef}
      className={className}
      loading={loadInitially ? undefined : "lazy"}
      {...props}
    />
  );
};

要使用此 LazyLoadImage 组件,只需使用图片的 srcalt 属性调用它:

ReactDOM.createRoot(document.getElementById("root")).render(
  <LazyLoadImage
    src="https://picsum.photos/id/1080/600/600"
    alt="Strawberries"
  />
);

请点击右下角的“Go Live”在端口 8080 上运行网络服务。然后,你可以刷新“Web 8080”标签页来预览网页。

总结

恭喜你!你已经完成了图片懒加载实验。你可以在 LabEx 中练习更多实验来提升你的技能。