React Router Loader阻塞组件渲染,如何实现并行渲染与数据获取?
解决React Router Loader阻塞组件渲染的方案
React Router的Loader默认会在路由匹配后先执行完异步逻辑,再渲染对应组件,所以会出现你遇到的延迟渲染问题。要实现组件与Loader数据并行加载,有几个实用的方法:
方法1:将数据逻辑移至组件内部
放弃使用路由Loader,在组件里通过useEffect发起异步请求,或者用React Query、SWR这类数据请求库处理。这样组件会先渲染,数据加载完成后再更新UI:
import { useEffect, useState } from 'react'; function HelloWorld() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { await new Promise(resolve => setTimeout(resolve, 5000)); // 模拟获取数据 setData('加载完成'); setLoading(false); }; fetchData(); }, []); return ( <div> Hello World {loading && <p>数据加载中...</p>} {!loading && <p>{data}</p>} </div> ); } const routerSample = createBrowserRouter([{ path: '/', element: <HelloWorld />, // 移除loader }])
方法2:使用嵌套路由拆分渲染
把不需要等待数据的基础UI放在父路由(无Loader),需要数据的部分放在子路由(带Loader)。父路由会立即渲染,子路由等Loader完成后再渲染:
import { Outlet, useLoaderData } from 'react-router-dom'; function ParentComponent() { return ( <div> Hello World {/* 这部分会立即渲染 */} <Outlet /> {/* 子路由内容会等Loader完成后渲染 */} </div> ); } function ChildComponent() { const data = useLoaderData(); return <p>{data}</p>; } const routerSample = createBrowserRouter([{ path: '/', element: <ParentComponent />, children: [{ path: '', element: <ChildComponent />, loader: async () => { await new Promise(resolve => setTimeout(resolve, 5000)); return '数据加载完成'; } }] }])
方法3:使用defer和useAsyncValue实现流式渲染
React Router支持用defer返回异步值,配合useAsyncValue和Suspense,让组件先渲染,异步数据加载完成后再填充内容:
import { defer, useAsyncValue, Suspense } from 'react-router-dom'; function HelloWorld() { return ( <div> Hello World <Suspense fallback={<p>数据加载中...</p>}> <DataComponent /> </Suspense> </div> ); } function DataComponent() { const data = useAsyncValue(); return <p>{data}</p>; } const routerSample = createBrowserRouter([{ path: '/', element: <HelloWorld />, loader: async () => { const fetchData = async () => { await new Promise(resolve => setTimeout(resolve, 5000)); return '数据加载完成'; }; // 用defer包装异步函数 return defer({ data: fetchData() }); } }])
内容的提问来源于stack exchange,提问作者Bryan Gonzales
相关产品推荐
相关产品推荐

