I am having trouble protecting routes in my simple react web application. I keep receiving the error Uncaught Error: [ProtectedRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
App.js
import React, { useState, useEffect} from 'react';
import { Routes, Route, useNavigate, BrowserRouter} from 'react-router-dom';
import './App.css';
import Login from './Login';
import Register from './Register';
import SecretsComponent from './SecretsComponent';
import PasswordRetriever from './GetSecretsComponent';
import Homepage from './Home';
import ProtectedRoute from './PrivateRoute';
function App() {
return (
<div className="App">
<Routes>
<Route index element={<Homepage />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<ProtectedRoute path="/savePassword" element={<SecretsComponent />} />
<ProtectedRoute path="/getPassword" element={<PasswordRetriever />} />
</Routes>
</div>
);
}
export default App;
PrivateRoutes.jsx
import React from "react";
import { Route, Navigate } from "react-router-dom";
import Cookies from "universal-cookie";
const cookies = new Cookies();
// receives component and any other props represented by ...rest
export default function ProtectedRoute({ component: Component, ...rest }) {
return (
// this route takes other routes assigned to it from the App.js and return the same route if condition is met
<Route
{...rest}
render={(props) => {
// get cookie from browser if logged in
const token = cookies.get("TOKEN");
// returns route if there is a valid token set in the cookie
if (token) {
return <Component {...props} />;
} else {
// returns the user to the landing page if there is no valid token set
return (
<Navigate
to={{
pathname: "/",
state: {
// sets the location a user was about to access before being redirected to login
from: props.location,
},
}}
/>
);
}
}}
/>
);
};
Login.jsx:
import React, { useState } from "react";
import axios from "axios";
import { Form, Button } from "react-bootstrap";
import Cookies from "universal-cookie";
const cookies = new Cookies();
export default function Login () {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [login, setLogin] = useState(false)
const handleSubmit = (e) => {
e.preventDefault();
console.log(email);
const configuration = {
method: "post",
url: "/login",
data: {
email,
password,
},
};
// make the API call
axios(configuration)
.then((result) => {
setLogin(true);
// set the cookie
cookies.set("TOKEN", result.data.token, {
path: "/",
});
// redirect user to the auth page
window.location.href = "/getPassword";
})
.catch((error) => {
console.log(error);
})
}
return (
<Form onSubmit={(e)=>handleSubmit(e)}>
{/* email */}
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter email"
/>
</Form.Group>
{/* password */}
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
name="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
</Form.Group>
{/* submit button */}
<Button
variant="primary"
type="submit"
onClick={(e) => handleSubmit(e)}
>
Login
</Button>
{/* display success message */}
{login ? (
<p className="text-success">You Are Logged in Successfully</p>
) : (
<p className="text-danger">You Are Not Logged in</p>
)}
</Form>
)
}
I then tried to follow react router v6 protected routing documentation, and changed my app.js to:
import React, { useState, useEffect } from 'react';
import { Routes, Route, useNavigate, BrowserRouter } from 'react-router-dom';
import './App.css';
import Login from './Login';
import Register from './Register';
import SecretsComponent from './SecretsComponent';
import PasswordRetriever from './GetSecretsComponent';
import Homepage from './Home';
import ProtectedRoute from './PrivateRoute';
function App() {
return (
<div className="App">
<Routes>
<Route index element={<Homepage />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route element={<ProtectedRoute path="/savePassword" />} />
<Route element={<ProtectedRoute path="/getPassword" />} />
</Routes>
</div>
);
}
export default App;
Which results in the browser telling me No routes matched location for "/savePassword"
and "/getPassword"
, and renders in a blank page missing all forms. The routes also do not look to be protected with the updated code.
Any guidance on correctly protected routes with react-router v6 would be greatly appreciated.