React Router 6.15.0加载器请求数据时页面完全空白问题求助
问题分析与解决
问题原因
你使用createBrowserRouter时,它默认会在渲染任何路由组件前,先执行所有匹配路由的loader函数。首页子路由配置的getApplications loader会在初始访问时先发起请求,只有等请求完成后才会渲染RootLayout和HomePage,这就导致了加载期间页面完全空白。
而你之前课程中的实现大概率采用了不同的路由模式(比如旧版BrowserRouter+Routes,未使用data loader),或者使用了defer延迟数据加载逻辑,让组件先渲染再加载数据。
修复方案
方案1:使用defer让组件先渲染,再异步加载数据
通过defer包装异步数据,让路由立即渲染组件,而非等待请求完成:
- 更新
applicationLoader.js
import { defer } from 'react-router-dom'; const getApplications = async () => { const token = localStorage.getItem('token'); try { // 将请求逻辑封装为异步函数,defer会立即返回,不阻塞组件渲染 const fetchApplications = async () => { const response = await axios.get(appsEndPoint(), { headers: { 'Content-Type': 'application/json', 'Authorization': `token ${token}` }, timeout: 30000 }); return response.data; }; return defer({ applications: fetchApplications() }); } catch (error) { if (isAxiosError(error)) { console.log(error); toast.error(error.message); return defer({ applications: Promise.reject(error) }); } } }; export default getApplications;
- 更新
HomePage.js处理异步状态
import { useLoaderData, useAsyncValue, useAsyncError } from 'react-router-dom'; const HomePage = () => { const { applications } = useLoaderData(); const data = useAsyncValue(applications); const error = useAsyncError(applications); // 数据加载中 if (data === undefined) { return <LoadingSpinner />; } // 加载出错 if (error) { return <div>加载失败,请稍后重试</div>; } console.log(data); return ( <> <PageHeader pageTitle='Αιτήσεις' hasBack={false} /> </> ); }; export default HomePage;
- 调整
RootLayout.js确保初始渲染
const RootLayout = () => { const navigate = useNavigate(); const navigation = useNavigation(); const token = localStorage.getItem('token'); const isPageLoading = navigation.state === 'loading'; useEffect(() => { if (!token) { navigate('/login'); } }, [token, navigate]); // token不存在时返回占位,避免空白 if (!token) { return null; } return ( <Layout> <Navbar /> <Layout> <PageContent> <Outlet /> {/* 加载状态交给HomePage处理,也可保留原isPageLoading判断 */} </PageContent> <PageFooter /> </Layout> </Layout> ); };
方案2:启用React Router未来特性,用startTransition处理加载
在创建router时启用future.v7_startTransition,让loader在后台运行,同时渲染组件,此时useNavigation().state会正确显示loading状态:
const router = createBrowserRouter( [ // 你的路由配置 ], { future: { v7_startTransition: true, }, } );
启用后,RootLayout中的isPageLoading判断会生效,加载期间会正常显示RootLayout和加载动画。
额外优化
- 确保
RootLayout在任何情况下都有返回值,避免token不存在时页面空白(比如返回null或加载组件)。 - 可在
RootLayout中统一处理路由加载状态,无需在子组件中重复编写加载逻辑。
内容的提问来源于stack exchange,提问作者Jim Zokas
相关产品推荐
相关产品推荐

