React页面FMP分数低,为什么首次内容渲染这么慢?

爱香 ☘︎ 阅读 11

我正在优化一个产品列表页面,用React+Axios加载数据后渲染列表,Lighthouse测FMP有4秒多,但代码已经用懒加载了。代码里用useEffect获取数据,但感觉首次渲染卡在某个环节…


function ProductList() {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    (async () => {
      const res = await axios('/api/products');
      setProducts(res.data); // 这里返回了500条数据
    })();
  }, []);

  return (
    <div>
      {products.map(product => (
        <ProductCard key={product.id} data={product} />
      ))}
    </div>
  );
}

我尝试过把ProductCard拆成Code Splitting,但FMP没改善。用Chrome检查发现,页面在渲染完500条数据后FMP才触发,这正常吗?是不是不应该在组件挂载时就加载全部数据?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
Des.东宁
你的问题核心在于首次渲染阻塞了FMP,原因是你在组件挂载时直接加载并渲染了500条数据。这种操作会导致React的DOM更新压力非常大,尤其是在低端设备或网络环境较差的情况下。

解决方案可以从几个效率更高的角度入手:

第一,分页或者虚拟列表。500条数据一次渲染肯定是不合理的,用户也不可能同时看到这么多内容。你可以改成每次只加载前20-50条数据,后续通过滚动加载更多,或者用像react-window这样的库实现虚拟列表,这样只会渲染当前视口内的元素,性能会大幅提升。

第二,数据获取时机可以优化。你现在的代码是在组件挂载后才开始请求数据,这会让页面白屏时间变长。可以考虑把数据请求提前到服务端渲染(SSR)阶段,比如用Next.js做服务端数据预取,这样用户访问时HTML已经包含首屏数据,FMP会显著提升。

第三,懒加载不是拆分组件就够的,关键是控制资源加载优先级。你提到ProductCard用了Code Splitting,但这个对FMP帮助有限,因为瓶颈是数据量和渲染压力,而不是组件代码体积。建议给axios加个超时设置,并且确保接口响应头启用了gzip压缩。

第四,检查一下ProductCard组件内部有没有不必要的复杂逻辑或重复计算。如果每个卡片都有一些昂贵的计算,可以用React.memo包裹避免重复渲染。

给你一个优化后的代码示例:
function ProductList() {
const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
const PAGE_SIZE = 20;

useEffect(() => {
let isMounted = true;
(async () => {
const res = await axios(/api/products?limit=${PAGE_SIZE}&offset=${(page - 1) * PAGE_SIZE});
if (isMounted) setProducts(prev => [...prev, ...res.data]);
})();
return () => { isMounted = false; }; // 防止内存泄漏
}, [page]);

const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 200) {
setPage(prev => prev + 1);
}
};

useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);

return (
<div>
{products.map(product => (
<ProductCard key={product.id} data={product} />
))}
</div>
);
}


总结一下:分页或者虚拟列表是最直接有效的优化手段,同时尽量让数据请求更早触发。别一股脑全塞给前端渲染,效率太低了。
点赞 3
2026-02-16 21:18