使用createBrowserRouter时SecureRoute包裹的DashboardView无法渲染
React Router SecureRoute 组件渲染问题排查与修复
问题描述
尝试实现SecureRoute组件,并使用createBrowserRouter配置路由,但被SecureRoute包裹的DashboardPresenter的子组件DashboardView无法渲染。相关代码如下:
相关代码
index.js
import SecureRoute from "./utils/SecureRoute"; import SecurityProvider from "./utils/SecurityProvider"; import { createBrowserRouter, RouterProvider} from "react-router-dom"; const router = createBrowserRouter([ { path: "/", element: <App />, errorElement: <ErrorView />, }, { path: "/signup", element: <SignUpPresenter />, errorElement: <ErrorView />, }, { path: "/login", element: <LogInPresenter />, errorElement: <ErrorView />, }, { path: "/dashboard", element: ( <SecureRoute> <DashboardPresenter /> </SecureRoute> ), errorElement: <ErrorView />, }, ]); const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <Provider store={store}> <SecurityProvider> <RouterProvider router={router} /> </SecurityProvider> </Provider> </React.StrictMode> );
SecureRoute.js
import React from "react"; import LogInPresenter from "../presenters/LogInPresenter"; import { Navigate, Outlet } from "react-router-dom"; import useSecurity from "./useSecurity"; const SecureRoute = () => { const { loggedIn } = useSecurity(); return loggedIn ? <Outlet /> : <Navigate to="login" />; }; export default SecureRoute;
SecurityProvider.js
import { React } from "react"; import SecurityContext from "./SecurityContext"; import { useDispatch, useSelector } from "react-redux"; const SecurityProvider = (props) => { const dispatch = useDispatch(); const { data: results, error, loading, } = useSelector((state) => state.user || {}); return ( <SecurityContext.Provider value={{ logIn: (email, password) => { dispatch({ type: "LOGIN", payload: { email: email, password: password }, }); }, logOut: () => { dispatch({ type: "LOGOUT" }); }, signUp: (email, password) => { dispatch({ type: "SIGNUP", payload: { email: email, password: password }, }); }, loggedIn: results, loading: loading, error: error, }} > {props.children} </SecurityContext.Provider> ); }; export default SecurityProvider;
DashboardPresenter.js
import DashboardView from "../views/DashboardView"; import useSecurity from "../utils/useSecurity"; function DashboardPresenter() { const { logOut, loggedIn, loading, error } = useSecurity(); function logOutACB() { console.log("Log the user out."); logOut(); } return <DashboardView logOut={logOutACB} loading={loading} />; } export default DashboardPresenter;
问题原因
- SecureRoute 实现与路由用法不匹配:当前
SecureRoute使用Outlet组件,Outlet是React Router嵌套路由的占位符,但你是将SecureRoute作为父组件直接包裹DashboardPresenter,这种场景下Outlet无法识别并渲染子组件。 - 登录状态判断逻辑有隐患:
SecurityProvider中loggedIn直接赋值为results,如果results是空对象或undefined,会导致loggedIn被判断为假,即使登录成功也可能无法正确渲染受保护路由。
修复方案
方案一:修改 SecureRoute 直接渲染子组件
调整SecureRoute接收children属性,适配当前路由配置方式:
// SecureRoute.js import React from "react"; import { Navigate } from "react-router-dom"; import useSecurity from "./useSecurity"; const SecureRoute = ({ children }) => { const { loggedIn } = useSecurity(); // 转换为布尔值,避免空对象等导致的判断错误 const isAuthenticated = !!loggedIn; return isAuthenticated ? children : <Navigate to="/login" replace />; }; export default SecureRoute;
方案二:改用嵌套路由结构
如果希望保留Outlet的用法,调整路由配置为嵌套结构:
// index.js const router = createBrowserRouter([ // ...其他路由 { element: <SecureRoute />, // 所有受保护路由放在children中 children: [ { path: "/dashboard", element: <DashboardPresenter />, errorElement: <ErrorView />, }, // 可添加更多受保护路由 ], }, ]);
额外优化:修正登录状态判断
在SecurityProvider中确保loggedIn为布尔值,避免非预期的真值判断:
// SecurityProvider.js value={{ // ...其他方法 loggedIn: !!results, // 转换为布尔值,确保登录状态判断准确 loading: loading, error: error, }}
验证
修改后,登录成功跳转到/dashboard时,SecureRoute会正确渲染DashboardPresenter,进而渲染DashboardView。
内容的提问来源于stack exchange,提问作者saner
相关产品推荐
相关产品推荐

