如何等待React组件完全渲染并绘制完成,渲染期间显示加载屏?
解决方案
你的核心需求是等待DOM渲染完成+浏览器绘制完成+所有媒体资源加载完成后再显示页面,避免用户看到绘制或资源加载过程,期间用加载屏占位。以下是具体实现方案:
为什么之前的方案不生效
- 懒加载:仅负责组件代码的延迟加载,和DOM渲染、浏览器绘制完全无关,无法解决你的问题。
- 空依赖
useEffect:在React的DOM提交阶段(即DOM结构更新完成)执行,但此时浏览器还未完成页面绘制,所以仍然会看到绘制过程。
方案一:仅等待DOM绘制完成(适合资源已预加载场景)
利用requestAnimationFrameAPI,它的回调会在浏览器下一次重绘前执行,确保DOM渲染完成且浏览器即将完成绘制时再隐藏加载屏。
import { useState, useEffect } from 'react'; function FormComponent() { const [loading, setLoading] = useState(true); useEffect(() => { const rafId = requestAnimationFrame(() => { // 此时DOM已渲染完成,浏览器即将完成绘制 setLoading(false); }); // 组件卸载时取消回调,避免内存泄漏 return () => cancelAnimationFrame(rafId); }, []); if (loading) { return <div className="loading-screen">加载中...</div>; } return ( <div className="form-component"> <video src="你的视频地址" controls></video> <img src="图片1地址" alt="图片1" /> <img src="图片2地址" alt="图片2" /> <img src="图片3地址" alt="图片3" /> {/* 其他表单内容 */} </div> ); } export default FormComponent;
方案二:等待DOM绘制+所有媒体资源加载完成(适配你的场景)
因为组件包含视频和图片这些异步加载的资源,即使DOM结构渲染完成,资源未加载完成时浏览器仍会二次绘制,所以需要同时监听资源加载状态:
import { useState, useEffect, useRef } from 'react'; function FormComponent() { const [loading, setLoading] = useState(true); const totalResources = useRef(4); // 1个视频 + 3张图片 const loadedResources = useRef(0); // 资源加载/失败时的统一处理函数 const handleResourceReady = () => { loadedResources.current += 1; if (loadedResources.current === totalResources.current) { // 所有资源就绪后,等待绘制完成再隐藏加载屏 const rafId = requestAnimationFrame(() => { setLoading(false); }); return () => cancelAnimationFrame(rafId); } }; useEffect(() => { // 给所有媒体元素绑定事件监听 const mediaElements = document.querySelectorAll('video, img'); mediaElements.forEach(el => { el.addEventListener('load', handleResourceReady); el.addEventListener('error', handleResourceReady); // 处理加载失败的情况,避免加载屏一直显示 }); // 组件卸载时移除监听 return () => { mediaElements.forEach(el => { el.removeEventListener('load', handleResourceReady); el.removeEventListener('error', handleResourceReady); }); }; }, []); if (loading) { return <div className="loading-screen">加载中...</div>; } return ( <div className="form-component"> <video src="你的视频地址" controls onLoad={handleResourceReady} onError={handleResourceReady}></video> <img src="图片1地址" alt="图片1" onLoad={handleResourceReady} onError={handleResourceReady} /> <img src="图片2地址" alt="图片2" onLoad={handleResourceReady} onError={handleResourceReady} /> <img src="图片3地址" alt="图片3" onLoad={handleResourceReady} onError={handleResourceReady} /> {/* 其他表单内容 */} </div> ); } export default FormComponent;
配套CSS优化(避免内容闪现)
给加载屏和目标组件添加样式,确保加载过程中组件内容完全不可见:
.loading-screen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: #fff; display: flex; align-items: center; justify-content: center; z-index: 9999; } .form-component { visibility: hidden; /* 默认隐藏组件 */ } .form-component.loaded { visibility: visible; /* 加载完成后显示 */ }
然后在组件中动态添加loaded类:
return ( <div className={`form-component ${!loading ? 'loaded' : ''}`}> {/* 组件内容 */} </div> );
内容的提问来源于stack exchange,提问作者MindYourBusiness
相关产品推荐
相关产品推荐

