You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何检测页面(含网络请求)完全加载?

解决方案

1. 利用原生window.load事件

window.load事件会在页面**所有资源(包括图片、样式表、脚本、字体、静态网络请求资源等)**加载完成后触发,完全匹配你需要全局检测页面完全加载的需求。

在React项目中,不要用useLayoutEffect(它仅在DOM渲染完成后执行,不等待资源加载),改用useEffect绑定该事件:

import { useEffect } from 'react';

function App() {
  useEffect(() => {
    function setupImageListeners() {
      // 所有资源加载完成,给页面所有图片绑定事件
      const allImages = document.querySelectorAll('img');
      allImages.forEach(img => {
        img.addEventListener('click', () => {
          console.log('图片被点击:', img.src);
          // 这里写你的业务逻辑
        });
      });
    }

    // 如果页面已经加载完成(比如刷新页面的场景),直接执行逻辑
    if (document.readyState === 'complete') {
      setupImageListeners();
    } else {
      window.addEventListener('load', setupImageListeners);
      // 组件卸载时移除监听,避免内存泄漏
      return () => window.removeEventListener('load', setupImageListeners);
    }
  }, []);

  return (
    // 你的应用内容
    <div>...</div>
  );
}

这个方案原生支持、无需额外依赖,能覆盖绝大多数静态资源的加载场景。

2. 监控动态网络请求完成

如果页面存在组件挂载后才发起的动态网络请求(比如异步fetch数据),window.load不会等待这类请求。这种情况可以用PerformanceObserver监控所有网络请求的完成状态:

import { useEffect, useState } from 'react';

function App() {
  const [allResourcesReady, setAllResourcesReady] = useState(false);

  useEffect(() => {
    const observer = new PerformanceObserver((list) => {
      const resourceEntries = list.getEntriesByType('resource');
      // 检查所有已记录的资源请求是否都已完成
      const allDone = resourceEntries.every(entry => entry.responseEnd > 0);
      // 结合document.readyState确保DOM和静态资源也加载完成
      if (allDone && document.readyState === 'complete') {
        setAllResourcesReady(true);
        observer.disconnect(); // 完成后停止监听
      }
    });

    observer.observe({ entryTypes: ['resource'] });

    // 初始检查:如果页面已经加载完成,直接校验请求状态
    if (document.readyState === 'complete') {
      const existingEntries = performance.getEntriesByType('resource');
      const allDone = existingEntries.every(entry => entry.responseEnd > 0);
      if (allDone) {
        setAllResourcesReady(true);
        observer.disconnect();
      }
    }

    return () => observer.disconnect();
  }, []);

  useEffect(() => {
    if (allResourcesReady) {
      // 所有静态资源+动态请求都完成,绑定图片事件
      const allImages = document.querySelectorAll('img');
      allImages.forEach(img => {
        img.addEventListener('click', () => console.log('图片点击:', img.src));
      });
    }
  }, [allResourcesReady]);

  return (
    <div>...</div>
  );
}

注意:对于跨域且未设置Timing-Allow-Origin响应头的请求,PerformanceObserver会屏蔽部分字段,需要后端配合配置响应头才能正常监控。

3. 全局状态跟踪组件加载状态

如果你的项目组件化程度高,每个组件都有独立的加载逻辑,可以用React Context(或Redux)实现全局加载状态跟踪,当所有组件都标记为加载完成后,再执行图片监听:

// 全局加载状态Context
import { createContext, useContext, useState, useEffect } from 'react';

const LoadingContext = createContext();

export function LoadingProvider({ children }) {
  const [loadingComponentIds, setLoadingComponentIds] = useState(new Set());

  // 注册组件为加载中
  const registerLoading = (componentId) => {
    setLoadingComponentIds(prev => new Set([...prev, componentId]));
  };

  // 标记组件加载完成
  const markComponentComplete = (componentId) => {
    setLoadingComponentIds(prev => {
      const newSet = new Set(prev);
      newSet.delete(componentId);
      return newSet;
    });
  };

  // 判断所有组件是否都加载完成
  const isAllComponentsLoaded = loadingComponentIds.size === 0;

  return (
    <LoadingContext.Provider value={{ registerLoading, markComponentComplete, isAllComponentsLoaded }}>
      {children}
    </LoadingContext.Provider>
  );
}

// 自定义Hook,用于子组件注册加载状态
export function useComponentLoading(componentId) {
  const { registerLoading, markComponentComplete } = useContext(LoadingContext);

  useEffect(() => {
    registerLoading(componentId);
    // 组件卸载时标记为完成
    return () => markComponentComplete(componentId);
  }, [componentId, registerLoading, markComponentComplete]);
}

// 根组件中监听全局加载完成
function App() {
  const { isAllComponentsLoaded } = useContext(LoadingContext);

  useEffect(() => {
    if (isAllComponentsLoaded) {
      // 所有组件加载完成,绑定图片事件
      const allImages = document.querySelectorAll('img');
      allImages.forEach(img => {
        img.addEventListener('click', () => console.log('图片点击:', img.src));
      });
    }
  }, [isAllComponentsLoaded]);

  return (
    <LoadingProvider>
      {/* 子组件示例:每个需要跟踪加载状态的组件调用useComponentLoading */}
      <UserList />
      <ProductGallery />
    </LoadingProvider>
  );
}

// 子组件示例
function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  // 注册当前组件的加载状态
  useComponentLoading('UserList');

  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <div>加载中...</div>;
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}

这个方案适合复杂的组件化项目,能精准跟踪每个业务组件的加载状态,确保所有业务逻辑完成后再执行后续操作。


内容的提问来源于stack exchange,提问作者alienbuild

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:25:34