如何在 React 中实现页面完全预加载(字体、图片、样式)后再显示
花韻仙語
发布时间:2026-01-16 23:37:02
|
689人浏览过
|
来源于php中文网
原创

通过 react 的 `` 组件配合代码分割与资源懒加载策略,可在客户端渲染中实现“全量资源就绪后才展示页面”,避免字体回退、图片渐进加载等闪烁问题。
在 React 客户端渲染(CSR)应用中,页面默认“边加载边渲染”,导致未加载完成的字体(如回退为 Times New Roman)、未解码的图片(模糊/占位/分块加载)或未注入的 CSS 样式会短暂暴露给用户,影响体验一致性与专业感。虽然 原生仅支持 异步组件(React.lazy) 的加载状态兜底,但结合现代前端工程实践,我们可通过以下组合方案实现「所有关键资源(字体、图片、内联样式、第三方组件)全部就绪后才首屏渲染」:
✅ 推荐架构:根级 Suspense + 资源预加载守卫
1. 使用 React.lazy + Suspense 包裹路由组件(基础层)
// App.tsx
import { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const HomePage = lazy(() => import('./pages/Home'));
const AboutPage = lazy(() => import('./pages/About'));
function App() {
return (
{/* 全局加载态:所有路由组件加载完成前显示 Loading */}
Loading… }>
} />
} />
);
}
export default App;
⚠️ 注意: 本身不自动等待图片或字体加载,它只拦截 lazy 组件的动态导入 Promise。因此需主动将关键静态资源“纳入加载依赖流”。
2. 预加载关键资源(字体 & 图片)作为加载依赖
利用 useEffect + Promise.all() 在根组件或布局组件中集中管控,避免每个组件重复处理:
// components/ResourceGuard.tsx
import { useState, useEffect } from 'react';
export function ResourceGuard({ children }: { children: React.ReactNode }) {
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const loadPromises: Promise[] = [];
// ✅ 预加载关键字体(Web Font Loader 或 CSS @font-face + font-display: optional)
// 示例:使用 FontFace API 确保自定义字体就绪
if (typeof document !== 'undefined') {
const font = new FontFace('Inter', 'url(/fonts/Inter.woff2)', {
weight: '400',
display: 'swap'
});
loadPromises.push(font.load().then(() => document.fonts.add(font)));
}
// ✅ 预加载首屏关键图片(如 banner、logo)
const imageUrls = ['/images/logo.png', '/images/hero.jpg'];
imageUrls.forEach(src => {
const img = new Image();
img.src = src;
loadPromises.push(
new Promise(resolve => {
img.onload = () => resolve();
img.onerror = () => resolve(); // 失败也继续,避免阻塞
})
);
});
// ✅ 等待所有资源加载完成
Promise.all(loadPromises).then(() => setIsReady(true));
}, []);
if (!isReady) {
return Preparing assets…
;
}
return <>{children}>;
}然后在 App.tsx 中包裹:
function App() {
return (
Loading page…