I am using react-router-dom
version 6.11.2 for my front-end routing in my App.js file:
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;
However, when routing to "/auth/new-user"
, the CreateUser
component is not rendered.
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;
CreateUser:
import styles from "./Login.module.css";
import react, { useState } from "react";
const CreateUser = () => {
console.log("create user rendered");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const handleSubmit = async (event) => {
event.preventDefault();
try {
// Validation: Check if passwords match
if (password !== confirmPassword) {
// Handle password mismatch error
return;
}
// Perform new user registration logic here
console.log("New user registered:", email, password);
} catch (error) {
console.log(error);
// Handle error
}
};
return (
<>
<div className={styles.loginForm}>
<h2>Create New User</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>
<div className={styles.formControl}>
<label htmlFor="confirmPassword">Confirm Password:</label>
<input
type="password"
id="confirmPassword"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
required
/>
</div>
<button type="submit">Register</button>
</form>
</div>
</>
);
};
export default CreateUser;
All my other front-end routing that is defined after the "/auth"
route, including the children routes work without any issues, and when I define the "/new-user"
route as an absolute path sibling to the "/auth"
route, CreateUser
renders properly. Is there some specific issue with nesting routes that I am not seeing?
If you would like CreateUser
to be rendered as a nested child route of the Login
component on "/auth"
then Login
necessarily should render an Outlet
component for the nested route(s) to render its/their element
content to.
See Layout Routes and Outlets for more details.
import React, { useState } from "react";
import {
Link,
Outlet, // <-- Import Outlet component
useNavigate
} from "react-router-dom";
import styles from "./Login.module.css";
import Title from "../../components/Layout/Title";
const Login = () => {
...
return (
<>
<Title />
<div className={styles.loginForm}>
<h2>Login</h2>
<form onSubmit={handleSubmit}>
...
</form>
<Link to={"new-user"}>Create New User</Link>
</div>
<Outlet /> {/* <-- Render Outlet for nested routes */}
</>
);
};
export default Login;
If you happen to instead only want Login
and CreateUser
to be "sibling" components, each rendered on their own page then demote the Login
component down to a nested route.
const clientRouter = createBrowserRouter(
createRoutesFromElements(
<>
<Route path="/auth"> {/* <-- Renders an Outlet by default */}
<Route
index {/* <-- Renders on parent's path, e.g. "/auth" */}
element={<Login />}
/>
<Route path="new-user" element={<CreateUser />} />
</Route>
<Route
path="/"
element={<RootLayout />}
errorElement={<NotFound404 />}
>
{/* children routes */}
</Route>
</>
)
);