React Router DOM 6.14:元素与Loader传参及全局加载态问题
React Router DOM 6.14 两个问题的解决方案
问题1:向loader传递Context/组件数据(避免用params)
Loader函数在组件渲染前执行,没法直接用useContext,但可以通过在组件内部创建路由的方式,把Context数据作为参数传给loader:
- 新建路由配置组件,在组件内获取Context数据
// RouterConfig.tsx import { useContext } from 'react'; import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { SiteContext } from './hooks/useContext'; import App from './App'; import ErrorPage from './ErrorPage'; import ProductsMain from './ProductsMain'; import { getItems } from './getItems'; export const RouterConfig = () => { // 拿到Context里的数据 const siteContext = useContext(SiteContext); const router = createBrowserRouter([ { path: "/", element: <App />, errorElement: <ErrorPage />, children: [ { path: "/products/:category", element: <ProductsMain />, // 把Context数据作为参数传给loader loader: (request) => getItems(request, siteContext), } ], } ]); return <RouterProvider router={router} />; };
- 修改
getItems函数接收额外参数
export async function getItems(request: any, contextData: any) { const body = { // 直接使用传递过来的Context数据 ...contextData, // 其他需要的字段 }; try { const url = `${urlBE}/products/${request.params.category}`; return await serverAPI(url, body, "success"); } catch (error: any) { throw new Error(error); } }
- 更新Index.tsx使用新的路由组件
import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import { RouterConfig } from "./RouterConfig"; import { SiteProvider } from "./hooks/useContext"; const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement); root.render( <React.StrictMode> <SiteProvider> <RouterConfig /> </SiteProvider> </React.StrictMode> );
这样Context更新时,路由会重新创建,loader也能拿到最新的数据。
问题2:全局实现loader加载动画
用React Router的useNavigation hook可以全局监听loader的加载状态,在根组件里统一处理:
- 修改根组件App(或者全局Layout组件)
import { useNavigation, Outlet } from 'react-router-dom'; function App() { const navigation = useNavigation(); // 判断是否有loader正在加载 const isLoading = navigation.state === 'loading'; return ( <div className="app-wrapper"> {/* 全局加载动画 */} {isLoading && ( <div className="global-spinner"> <span>加载中...</span> {/* 这里可以替换成你的Spinner组件 */} </div> )} {/* 子路由内容 */} <Outlet /> </div> ); }
- 给全局Spinner加样式(示例)
.global-spinner { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; z-index: 9999; }
只要任何路由的loader在请求数据,navigation.state就会变成loading,全局Spinner就会自动显示/隐藏。
内容的提问来源于stack exchange,提问作者Bennyh961
相关产品推荐
相关产品推荐

