You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router嵌套路由子组件无法渲染问题求助

React Router v6 嵌套路由子组件不渲染问题解决

问题描述

使用react-router-dom 6.11.2配置嵌套路由后,访问/auth/new-user时CreateUser组件无法渲染,仅Login组件内容显示;若将new-user设为/auth的同级绝对路由,组件可正常渲染。

App.js 路由配置代码

import "./App.css";
import {
  Route,
  RouterProvider,
  createBrowserRouter,
  createRoutesFromElements,
} from "react-router-dom";
import RootLayout from "./layouts/RootLayout";
import { UserContextProvider } from "./store/user-context";
import NotFound404 from "./components/Utility/NotFound404";
import Login from "./pages/general/Login";
import CreateUser from "./pages/general/CreateUser";

const clientRouter = createBrowserRouter(
  createRoutesFromElements(
    <>
      <Route path="/auth" element={<Login />}>
        <Route path="new-user" element={<CreateUser />} />
      </Route>
      <Route path="/" element={<RootLayout />} errorElement={<NotFound404 />}>
        {/* children routes */}
      </Route>

    </>
  )
);

function App() {
  return (
    <>
      <UserContextProvider>
        <RouterProvider router={clientRouter}></RouterProvider>
      </UserContextProvider>
    </>
  );
}

export default App;

Login 组件原代码

import React, { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import styles from "./Login.module.css";
import Title from "../../components/Layout/Title";

const Login = () => {
  console.log("login rendered");
  const navigate = useNavigate();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = async (event) => {
    event.preventDefault();

    console.log("Login submitted:", email, password);

    try {
      const response = await fetch("http://localhost:8000/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password }),
      });

      if (response.ok) {
        //do something
      } else {
        //do something
      }
    } catch (error) {
      console.log(error);
      //handle error
    }
  };

  return (
    <>
      <Title />
      <div className={styles.loginForm}>
        <h2>Login</h2>
        <form onSubmit={handleSubmit}>
          <div className={styles.formControl}>
            <label htmlFor="email">Email:</label>
            <input
              type="email"
              id="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </div>
          <div className={styles.formControl}>
            <label htmlFor="password">Password:</label>
            <input
              type="password"
              id="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <button type="submit">Login</button>
        </form>
        <Link to="new-user">Create New User</Link>
      </div>
    </>
  );
};

export default Login;

问题原因

React Router v6 中,嵌套路由的子组件必须通过父路由组件中的 <Outlet /> 来挂载渲染。当前Login组件未导入并使用<Outlet />,导致子路由/auth/new-user对应的CreateUser组件没有渲染的容器位置。

解决方案

修改Login组件,导入Outlet并在合适位置添加该组件,为子路由组件提供渲染入口:

修改后的Login组件代码

import React, { useState } from "react";
import { Link, useNavigate, Outlet } from "react-router-dom"; // 新增Outlet导入
import styles from "./Login.module.css";
import Title from "../../components/Layout/Title";

const Login = () => {
  console.log("login rendered");
  const navigate = useNavigate();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = async (event) => {
    event.preventDefault();

    console.log("Login submitted:", email, password);

    try {
      const response = await fetch("http://localhost:8000/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password }),
      });

      if (response.ok) {
        //do something
      } else {
        //do something
      }
    } catch (error) {
      console.log(error);
      //handle error
    }
  };

  return (
    <>
      <Title />
      <div className={styles.loginForm}>
        <h2>Login</h2>
        <form onSubmit={handleSubmit}>
          <div className={styles.formControl}>
            <label htmlFor="email">Email:</label>
            <input
              type="email"
              id="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </div>
          <div className={styles.formControl}>
            <label htmlFor="password">Password:</label>
            <input
              type="password"
              id="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <button type="submit">Login</button>
        </form>
        <Link to="new-user">Create New User</Link>
      </div>
      {/* 添加Outlet,子路由组件将渲染在此处 */}
      <Outlet />
    </>
  );
};

export default Login;

可选优化:访问子路由时隐藏父组件内容

如果希望访问/auth/new-user时只显示CreateUser组件、隐藏Login表单,可以通过useMatch判断当前路由,控制内容显示:

import { Link, useNavigate, Outlet, useMatch } from "react-router-dom";

const Login = () => {
  const isNewUserRoute = useMatch("/auth/new-user");
  
  // ...其他逻辑代码
  
  return (
    <>
      <Title />
      {/* 仅在非new-user路由时显示Login表单 */}
      {!isNewUserRoute && (
        <div className={styles.loginForm}>
          <h2>Login</h2>
          {/* 表单及链接代码 */}
        </div>
      )}
      <Outlet />
    </>
  );
};

内容的提问来源于stack exchange,提问作者KapteinKonyn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 08:02:02