React-Admin集成React-Router后路由异常问题排查求助
问题:React-Admin集成React-Router后路由异常
将React-Admin的AdminDashboard拆分为独立组件并集成到React-Router管理的应用中后,出现页面加载失败、URL异常跳转的问题:原本应显示http://localhost:3000/AdminDashboard/#/users,现在直接跳转到http://localhost:3000/users或/posts,仅拆分组件后出现该问题。
重构前正常的App.js代码
// 所有导入语句 const app = () => { return ( <Admin dataProvider={dataProvider}> <Resource name="posts" list={PostList} /> <Resource name="users" list={UserList} /> </Admin> ); }; // 导出组件,此时代码运行正常
当前异常的代码结构
AdminDashboard.jsx
import React from 'react'; import { Admin, Resource } from 'react-admin'; import UserList from './User'; import PostList from './Posts'; import restProvider from 'ra-data-simple-rest'; const dataProvider = restProvider('http://localhost:3000'); const AdminDashboard = () => { return ( <Admin dataProvider={dataProvider}> <Resource name="posts" list={PostList} /> <Resource name="users" list={UserList} /> </Admin> ); }; export default AdminDashboard;
App.js
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Header from "./components/Layout/Header"; import Footer from "./components/Layout/Footer"; import Homepage from "./components/Homepage"; import NotFound from "./components/Layout/NotFound"; import PrivateRoute from "./components/Routing/PrivateRoute"; import Login from "./components/Admin/Login"; import AdminDashboard from "./components/Admin/AdminDashboard"; const App = () => { return ( <Router> <div className="App"> <Routes> <Route path="/" element={<LayoutsWithHeader />}> <Route path="*" element={<NotFound />} /> <Route exact path="/" element={<Homepage />} /> <Route path="/login" element={<Login />} /> <Route element={<PrivateRoute />}> <Route path="/AdminDashboard/*" element={<AdminDashboard />} /> </Route> </Route> </Routes> </div> </Router> ); }; const LayoutsWithHeader = () => { return ( <> <Header /> <Outlet /> <Footer /> </> ); }; export default App;
range.js
module.exports = (req, res, next) => { res.header("Content-Range", "users 0-20/20"); res.header("Content-Range", "Posts 0-20/20"); next(); };
项目代码结构
appname/ ├── client/ # 客户端React应用 │ ├── public/ # 静态文件 │ ├── src/ │ │ ├── components/ │ │ │ ├── Admin/ │ │ │ │ ├── AdminDashboard.jsx # 后台仪表盘组件 │ │ │ │ ├── Login.jsx # 登录组件 │ │ │ │ ├── Posts.jsx # 帖子组件 │ │ │ │ └── Users.jsx # 用户组件 │ │ │ ├── Layout/ │ │ │ │ ├── Footer.jsx # 页脚布局组件 │ │ │ │ ├── Header.jsx # 页眉布局组件 │ │ │ │ └── NotFound.jsx # 404组件 │ │ │ ├── Routing/ │ │ │ │ └── PrivateRoute.jsx # 私有路由组件 │ │ │ └── Homepage.jsx # 首页组件 │ │ ├── App.css # 应用主CSS文件 │ │ ├── App.js # React应用主文件 │ │ ├── App.test.js # 应用测试文件 │ │ ├── index.css # 入口文件CSS │ │ ├── index.js # React应用入口 │ │ ├── logo.svg # 图标文件 │ │ ├── reportWebVitals.js # Web性能报告工具 │ │ └── setupTests.js # 测试配置文件 │ ├── package.json # 客户端依赖配置 │ └── node_modules/ # 客户端依赖包 │ ├── server/ # 服务端Node.js应用 │ ├── Controllers/ # 服务端逻辑控制器 │ ├── middlewares/ # 服务端中间件 │ ├── Models/ # 数据模型 │ ├── Routers/ # 路由定义 │ ├── config/ │ │ └── config.env # 环境配置文件 │ ├── node_modules/ # 服务端依赖包 │ ├── uploads/ # 上传文件目录 │ ├── package-lock.json # 服务端依赖锁定文件 │ ├── package.json # 服务端依赖配置 │ ├── range.js # 自定义中间件文件 │ ├── server.js # Node.js服务入口 │ └── db.json # 模拟数据库JSON文件 │ ├── .gitignore # Git忽略配置 ├── links.json # 额外JSON文件 ├── package-lock.json # 根目录依赖锁定文件 ├── package.json # 根目录依赖配置 ├── README.md # 项目说明文档 └── request.log # 服务端请求日志
额外信息
Header中的跳转链接
<Link to="/AdminDashboard"> AdminDashboard </Link>
客户端package.json部分内容
"proxy": "http://localhost:5000", "dependencies": { "react": "^18.2.0", "react-admin": "^4.16.4", "react-dom": "^18.2.0",
服务端package.json部分内容
"scripts": { "server": "json-server --watch db.json --port 5000 --middlewares ./range.js", "client": "npm start --prefix ./client", "dev": "concurrently \"npm run server\" \"npm run client\"" },
解决方案
问题根源是React-Admin默认使用哈希路由(HashRouter),与外层的BrowserRouter冲突,导致路由跳转时丢失/AdminDashboard前缀,以下是两种可行修复方案:
方案1:给React-Admin设置独立的BrowserRouter与basename
修改AdminDashboard.jsx,用BrowserRouter包裹Admin组件,并指定basename为/AdminDashboard:
import React from 'react'; import { Admin, Resource } from 'react-admin'; import { BrowserRouter } from 'react-router-dom'; import UserList from './User'; import PostList from './Posts'; import restProvider from 'ra-data-simple-rest'; const dataProvider = restProvider('http://localhost:3000'); const AdminDashboard = () => { return ( <BrowserRouter basename="/AdminDashboard"> <Admin dataProvider={dataProvider} disableTelemetry> <Resource name="posts" list={PostList} /> <Resource name="users" list={UserList} /> </Admin> </BrowserRouter> ); }; export default AdminDashboard;
方案2:让React-Admin复用外层Router(推荐)
通过自定义导航函数,让React-Admin适配外层的BrowserRouter,避免嵌套路由冲突:
import React from 'react'; import { Admin, Resource } from 'react-admin'; import { useNavigate } from 'react-router-dom'; import UserList from './User'; import PostList from './Posts'; import restProvider from 'ra-data-simple-rest'; const dataProvider = restProvider('http://localhost:3000'); const AdminDashboard = () => { const navigate = useNavigate(); // 自定义导航函数,给React-Admin的路由添加外层前缀 const customNavigate = (path) => { navigate(`/AdminDashboard${path}`); }; return ( <Admin dataProvider={dataProvider} navigate={customNavigate} disableTelemetry > <Resource name="posts" list={PostList} /> <Resource name="users" list={UserList} /> </Admin> ); }; export default AdminDashboard;
额外修复:修正range.js的Content-Range头
原代码中第二个头会覆盖第一个,应根据请求路径动态设置:
module.exports = (req, res, next) => { if (req.path.includes('/users')) { res.header("Content-Range", "users 0-20/20"); } else if (req.path.includes('/posts')) { res.header("Content-Range", "posts 0-20/20"); } next(); };
内容的提问来源于stack exchange,提问作者husam saleh
相关产品推荐
相关产品推荐

