loader
每个路由都可以定义一个“加载器”函数,在渲染路由元素之前为路由组件提供数据。
仅当使用数据路由时,此功能才有效。
createBrowserRouter([
{
path: '/',
element: <App/>,
loader: async () => {
return fetch("https://httpbin.org/get")
},
children: [
{
path: 'home',
element: <Home/>,
loader: async () => {
return fetch("https://httpbin.org/get")
},
}
]
}
])当用户在应用程序中进行导航时,将并行调用下一个匹配路由分支的加载器,并通过useLoaderData将其数据提供给组件。
params
params是从动态路由段中解析出来的参数,并传递给加载器:
路径中的:id被解析为相同名称的params.id
request
最常见的用例是创建 URL,并从中读取URLSearchParams。
返回响应
从loader中你可以返回任何你想要返回的数据,并从useLoaderData中得到它,甚至可以在loader中进行网络请求,例如:
React Router 会自动调用 response.json() ,因此组件在渲染时不需要解析它:
您也可以自己构建响应:
抛出异常
你可以在加载器中使用throw来跳出当前堆栈的,React Router 将渲染异常组件errorElement。
延迟数据❓
上述事例中,我们通过sleep函数来模拟网络请求,我们会发现在慢速网络中,loader中的网络请求会导致导航的延迟跳转和视图的渲染。在网络非常慢的情况下,loader会直到请求得到响应后,才进行路由的跳转和视图的渲染,这将会导致页面的加载或跳转到该路由所需的时间被拉长。为了改善这一点:
使用
promise.all并行加载数据。添加全局过渡效果(有助于改善用户体验)。
添加骨架屏(有助于改善用户体验)。
如果这些方法不起作用,我们不得不将网络请求从loader中移除,转而在组件中获取数据。
但是在大多数情况下仍然是不太理想的,特别是当你正在对路由组件进行代码拆分,原因有两个:
客户端将数据请求放在瀑布流上:文档 -> JavaScript -> 懒加载路由 -> 数据获取。
你的代码不能轻松地在组件获取和路由获取之间切换。
解决方案✅
React Router 利用 React18 的Suspense通过defer响应工具和<Await>组件或useAsyncValue钩子来进行数据获取。通过使用这些API,你可以解决以下两个问题:
你的网络请求不再在瀑布流上:文档 -> JavaScript -> 路由懒加载和获取数据(并行)。
你可以轻松地在回退渲染和等待数据之间切换。
使用Suspense和Await包裹延迟渲染的视图,以便在渲染回退UI时候使用,使用defer包裹延迟的数据。
或者你也可以使用
useAsyncValue钩子,但你需要将代码分离到另一个组件中:
现在,我们不必等得到响应数据,在进行导航的跳转,而是在用户跳转新路由时立即获取数据。在网速较慢的情况下,此处会展示你所提供的loading状态。如果请求失败它会显示errorElement,请求成功则显示你所提供的视图。
此外,你还可以根据是否包含await关键字来切换某些内容是否被延迟。
为什么加载器返回的响应对象不再起作用?
当你使用defer时,你告诉了 React Router 立即加载页面,而不是延迟加载。页面在 Response 对象返回之前已经加载,因此响应不会像使用return fetch()一样自动处理。
你需要处理自己的 Response,并解析延迟的 Promise,而不是 Promise 实例。
甚至,我们可以嵌套多层网络请求。
最后更新于
这有帮助吗?