react-admin创建动态资源时useLocation、useHistory钩子返回undefined报错
问题原因
- 违反React钩子调用规则:你将
AdminResources作为普通函数直接调用AdminResources(),而不是以React组件形式<AdminResources />渲染,钩子无法在普通函数调用流程中正常工作。 - React Router上下文缺失:
react-router-dom的useLocation、useHistory等钩子必须在被Router上下文包裹的组件内部调用。而你调用AdminResources()的位置是在<Admin>组件的子节点声明阶段,此时<Admin>内部的Router上下文还未初始化,自然拿不到路由相关的值。 - react-admin
组件限制 :<Resource>只能直接作为<Admin>的直接子节点使用,不能嵌套在自定义组件内部返回。
解决方法
方案1:使用子节点函数特性(推荐)
react-admin的
修改你的App.js代码如下:
import React from "react"; import { Admin, Resource } from "react-admin"; import RoomList from "../components/Room"; import MyLoginPage from "./pages/MyLoginPage"; import HomePage from "./pages/HomePage"; import customRoutes from "./customRoutes"; import MyLayout from "./components/Layout/MyLayout"; import ClassroomPage from "./pages/ClassroomPage"; import authProvider from "./utils/authProvider"; import dataProvider from "./utils/dataProvider"; function App() { return ( <Admin dashboard={HomePage} loginPage={MyLoginPage} customRoutes={customRoutes} authProvider={authProvider} layout={MyLayout} dataProvider={dataProvider("http://localhost:5000/org")} disableTelemetry > <Resource name="classroom" {...ClassroomPage} /> {/* 传入函数作为子节点,参数包含router相关属性 */} {(routerContext) => { const location = routerContext.location; const resourceName = location?.pathname; let id = ""; if (resourceName) { const roomId = resourceName.split("/")[2]; id = roomId; } // 匹配到对应路由时返回动态Resource if (id && resourceName === `/room/${id}`) { return <Resource name={`room/${id}`} list={RoomList} /> } return null; }} </Admin> ); } export default App;
你可以直接删除原来的AdminResources组件,逻辑直接迁移到这个函数里即可。
方案2:版本适配调整
如果你的react-admin是v4版本,内部使用的是react-router v6,已经移除了useHistoryAPI,替换为useNavigate。如果要保留单独的AdminResources组件,需要将组件挂载到customRoutes中,确保组件在Router上下文内渲染后再处理动态资源逻辑。
额外注意事项
- 动态生成的资源name如果包含斜杠,需要确保你的dataProvider能正确处理带参数的资源名称,避免接口请求路径错误。
- 如果需要更复杂的动态资源注册,也可以在dataProvider层处理路径替换,不需要在资源定义阶段拼接id。
内容的提问来源于stack exchange,提问作者sourav ojha
相关产品推荐
相关产品推荐

