如何在Gatsby站点加载大体积page-data.json时显示加载器?
嘿,这个问题我在Gatsby项目里踩过坑!你遇到的核心问题是Gatsby的页面渲染逻辑:首次加载时,HTML骨架会先返回,但page-data.json(就是你说的10MB数据文件)是异步加载的,这时候组件里的数组可能已经被初始化(比如空数组或者构建时的默认值),导致array.length判断失效。下面给你几个靠谱的解决方案:
1. 最稳妥:修改Gatsby的HTML模板(处理首次加载)
这个方法能直接覆盖首次加载时page-data.json下载的空档,因为HTML是最先渲染的,加载动画会立刻显示,直到Gatsby完成初始化。
首先在src/html.js里(如果没有就从Gatsby默认模板复制一份),在Gatsby的根容器前加加载动画:
<body> <!-- 加载动画容器 --> <div id="initial-loading"> <div class="spinner"></div> </div> <div id="___gatsby"></div> <script> // 监听页面完全加载(包括page-data),然后隐藏动画 window.addEventListener('load', () => { // 加个小延迟避免闪烁 setTimeout(() => { document.getElementById('initial-loading').style.display = 'none'; }, 200); }); </script> </body>
然后加对应的CSS(可以放在全局样式文件里):
#initial-loading { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: #fff; /* 匹配你的页面背景色 */ display: flex; justify-content: center; align-items: center; z-index: 9999; } .spinner { width: 50px; height: 50px; border: 4px solid #e0e0e0; border-top-color: #1976d2; /* 用你的主题色 */ border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
2. 组件级控制:如果数据是客户端动态加载
如果你的视频卡数据不是预渲染在page-data里,而是组件mount后才fetch的,那直接用组件内部状态就能解决:
import React, { useState, useEffect } from 'react'; import { FixedSizeList as List } from 'react-window'; const VideoCardList = () => { const [videos, setVideos] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { const loadVideos = async () => { // 替换成你的数据请求逻辑 const res = await fetch('/api/videos'); const videoData = await res.json(); setVideos(videoData); setIsLoading(false); }; loadVideos(); }, []); // 加载中显示spinner if (isLoading) { return ( <div style={{ display: 'flex', justifyContent: 'center', padding: '2rem' }}> <div className="spinner"></div> </div> ); } // 渲染react-window列表 return ( <List height={600} itemCount={videos.length} itemSize={120} width="100%" > {({ index, style }) => ( <div style={style} className="video-card"> {/* 你的视频卡内容 */} {videos[index].title} </div> )} </List> ); }; export default VideoCardList;
3. 进阶:监听page-data.json的加载事件
如果你非要直接检测page-data.json的加载状态,可以用一个自定义Hook来监听fetch请求:
import React, { useState, useEffect } from 'react'; const usePageDataLoaded = () => { const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const handleFetch = (event) => { const requestUrl = event.request.url; // 判断是否是page-data请求 if (requestUrl.includes('/page-data/') && requestUrl.endsWith('page-data.json')) { // 克隆请求并跟踪完成状态 event.request.clone().then(() => setIsLoaded(true)) .catch(() => setIsLoaded(true)); // 出错也标记为完成 } }; window.addEventListener('fetch', handleFetch); // 初始化时检查是否已经加载完成 if (window.__GATSBY__?.pageData) { setIsLoaded(true); } return () => window.removeEventListener('fetch', handleFetch); }, []); return isLoaded; }; // 在主页组件中使用 const HomePage = () => { const pageDataLoaded = usePageDataLoaded(); if (!pageDataLoaded) { return <div id="initial-loading"><div className="spinner"></div></div>; } return <VideoCardList />; };
这个方法有点依赖Gatsby的内部实现,但当前版本(v4/v5)是有效的,适合需要精确控制的场景。
内容的提问来源于stack exchange,提问作者Kyle Pennell
相关产品推荐
相关产品推荐

