Uncaught Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes> - node.js

After implemented Private Route I keep getting this error.
The problem appears when Im trying to get to the Profile page that nested in the .
App.js
import './App.css';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import LoginPage from './pages/LoginPage';
import SignUpPage from './pages/SignUpPage';
import ProfilePage from './pages/ProfilePage';
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';
import AdditionalItemPage from './pages/AdditionalItemPage';
import ReturnOfVehiclePage from './pages/ReturnOfVehiclePage';
import PolicyPage from './pages/PolicyPage';
import CarPage from './pages/CarPage';
import CarListPage from './pages/CarsListPage';
import NavBar from './NavBar';
import Footer from './Footer';
import NotFoundPage from './pages/NotFoundPage';
import { PrivateRoute } from './auth/PrivateRoute';
function App() {
return (
<BrowserRouter>
<div className="App">
<NavBar />
<div>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignUpPage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/cars" element={<CarListPage />} />
<Route path="/cars/:carId" element={<CarPage />} />
<Route path="/additional-item" element={<AdditionalItemPage />} />
<Route path="/return-vehicle" element={<ReturnOfVehiclePage />} />
<Route path="/policy" element={<PolicyPage />} />
<Route
path="/profile"
element={
<PrivateRoute>
<ProfilePage />
</PrivateRoute>
}
/>
<Route path="*" element={<NotFoundPage />} />
</Routes>
</div>
<Footer />
</div>
</BrowserRouter>
);
}
export default App;
PrivateRoute.js comp
import { Route, Navigate } from 'react-router-dom';
import { useUser } from './useUser';
export const PrivateRoute = (props) => {
const user = useUser();
if (!user) return <Navigate to="/login" />;
return <Route {...props} />;
};
I've already tried to wrap everyting I though of in the
The actual Profile paga into Routes
The PrivteRoute into Routes
The Route into another Routes
Creating another Routes, separeted with the 1st one.
If remove PrivateRoute, everything works fine but it s not the solution I'm looking for.

You just didn't implement it properly , just change your PrivateRoute.js component like this :
import { Navigate } from 'react-router-dom';
import { useUser } from './useUser';
function PrivateRoute({ children }) {
const user = useUser();
return user ? children : <Navigate to="/login" />;
}

The error message is accurate in that a Route must be directly placed within a Routes wrap. To get around this, simply create a 2nd top-level Routes wrap and move the Route logic out of your PrivateRoute.tsx file.
Consider this example sandbox I created with some slight modifications to your code. You can switch user to false/true to see how the /profile private route reacts as expected.
Here's the bare-bones implementation:
App.tsx
import { BrowserRouter, Route, Routes } from "react-router-dom";
import PrivateRoutes from "./PrivateRoutes";
function App() {
return (
<BrowserRouter>
<div className="App">
<div>
<Routes>
<Route path="/" element={<div>Hello World</div>} />
</Routes>
<PrivateRoutes /> {/* <---- all private routes ---- */}
</div>
</div>
</BrowserRouter>
);
}
export default App;
PrivateRoutes.tsx
import { Route, Routes } from "react-router-dom";
import PrivateRoute from "./PrivateRoute";
export default function PrivateRoutes() {
return (
<Routes>
<Route
path="/profile"
element={
<PrivateRoute>
<div>Private Profile</div>
</PrivateRoute>
}
/>
</Routes>
);
}
PrivateRoute.tsx
import { ReactNode } from "react";
import { Navigate } from "react-router-dom";
interface PropsI {
children: ReactNode;
}
export default function PrivateRoute({ children }: PropsI) {
const user = false;
if (!user) return <Navigate to="/fail" />;
return <>{children}</>;
}

Related

How can I navigate to Sign in page if the user is not login?

I want to navigate to the Signin page if the user is not login. But if the user is login then it will automatically navigate to home page, but I am not able to navigate to Sign in page when user is not login. I am pasting the code below. Kindly help me if you can.
Here is my App.js code
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import "./App.css";
import { Home } from "./containers/Home";
import { Signin } from "./containers/Signin";
import { Signup } from "./containers/Signup";
import PrivateRoute from "./components/HOC/PrivateRoute";
function App() {
return (
<div className="App">
<BrowserRouter>
<Routes>
<PrivateRoute path="/" element={<Home />} />
<Route path="/signin" element={<Signin />} />
<Route path="/signup" element={<Signup />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
Private route code is below
import React from "react";
import { Route , Navigate } from "react-router-dom";
const PrivateRoute = ({element:Component , ...rest})=>{
return <Route {...rest} element={(props)=>{
const token = window.localStorage.getItem('token');
if(token){
return <Component {...props} />
}else{
return <Navigate to={'/signin'}/>
}
}} />
}
export default PrivateRoute;`
I have tried many things but they didn't work. Kindly help me
You should add exact to your path '/' else any path starting by '/' will be routed to your Home component:
<PrivateRoute path="/" exact element={<Home />} />

how to set condition in react router DOM version 6?

I want to convert this code which has been written in react router v5 to v6 but I don't know how to do it, in general I want to set if the user doesn't have an account, redirect them to registration page an so on.
I'm aware of switch change and redirect the only problem is in this line of code :
<Route exact path="/">
{user ? <Home /> : <Redirect to="/register" />}
</Route>
the whole code:
import "./app.scss";
import Home from "./pages/home/Home";
import Register from "./pages/register/Register";
import Watch from "./pages/watch/Watch";
import Login from "./pages/login/Login";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
import { useContext } from "react";
import { AuthContext } from "./authContext/AuthContext";
const App = () => {
const { user } = useContext(AuthContext);
return (
<Router>
<Switch>
<Route exact path="/">
{user ? <Home /> : <Redirect to="/register" />}
</Route>
<Route path="/register">
{!user ? <Register /> : <Redirect to="/" />}
</Route>
<Route path="/login">{!user ? <Login /> : <Redirect to="/" />}</Route>
{user && (
<>
<Route path="/movies">
<Home type="movie" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</>
)}
</Switch>
</Router>
);
};
export default App;
You can use the element prop of v6, you don't need to use an exact prop on <Route path="/"> anymore. This is because all paths match exactly by default. If you want to match more of the URL because you have child routes use a trailing * as <Route path="/*" />.
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
.
.
.
return (
<BrowserRouter>
<Routes>
<Route path="/" element={user ? <Home /> : <Navigate to="/register" replace />} />
.
.
.
</Routes>
</BrowserRouter>
)
.
.
.
Also you can see more detail in reactrouter docs:
https://reactrouter.com/docs/en/v6/getting-started/overview

page does not redirect after setting token with localstorage

I am following the tutorial below to create a token system for my login application.
https://www.digitalocean.com/community/tutorials/how-to-add-login-authentication-to-react-applications
Here is my code:
App.js:
import logo from './logo.svg';
import './App.css';
import "bootstrap/dist/css/bootstrap.min.css";
import useToken from './components/useToken';
import Navbar from './components/Navbar';
import AudioDropzone from './components/AudioDropzone';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useLocation
} from "react-router-dom";
import Upload from './pages/Upload';
import Manage from './pages/Manage';
import Menu from './pages/Menu';
import Admin from './pages/Admin';
import Login from './pages/Login';
import { useEffect, useState } from 'react';
<script src="https://unpkg.com/boxicons#latest/dist/boxicons.js"></script>
function App() {
const { token, setToken } = useToken();
console.log(token)
if(!token) {
return(
<div className="App">
<div className="row">
<div class="col-2">
</div>
<div class="col-9">
<Login setToken={setToken} />
</div>
</div>
</div>
);
}
return (
<div className="App">
<Router>
<head>
<link rel="stylesheet" href="boxicons.min.css" />
</head>
<div className="row" >
<div class="col-2">
</div>
<div class="col-9">
<Switch>
<Route path="/upload">
<Upload customer_id={token}/>
</Route>
<Route path="/manage">
<Manage customer_id={token} />
</Route>
<Route path="/menu">
<Menu customer_id={token} />
</Route>
<Route path="/admin">
<Admin />
</Route>
<Route path="/admin/upload">
<Upload />
</Route>
<Route path="/admin/manage">
<Manage />
</Route>
<Route path="/admin/menu">
<Menu />
</Route>
</Switch>
</div>
</div>
</Router>
</div>
);
}
export default App;
useToken.js:
import { useState } from 'react';
export default function useToken() {
const getToken = () => {
const tokenString = localStorage.getItem('token');
const userToken = JSON.parse(tokenString);
return userToken?.token
};
const [token, setToken] = useState(getToken());
const saveToken = userToken => {
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken.token);
};
return {
setToken: saveToken,
token
}
}
Currently, when login is successful, it just clears the fields and shows the same login page again without showing the second version of App with all of my content. The issue is that the token value is not being updated and populated. I have verified that upon logging in token is updated to an integer value like 13.
This is seen when I log the value of userToken in useToken.js:
const saveToken = userToken => {
console.log(userToken) //returns 13
localStorage.setItem('token', JSON.stringify(userToken));
setToken(userToken.token);
};
Let me know what I am doing wrong!
I believe the bug is in the saveToken function.
setToken(userToken.token); should be setToken(userToken);
You don't need the .token because userToken is not an object. It is just an integer value.

react router dom: redirect and router: all urls are getting redirected, how to stop

I have the following reactjs code.
I am using react-router-dom V5
import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import { Router, Route, Switch, Redirect } from "react-router-dom";
import Login from "./views/User/Login";
import Signup from "./views/User/SignUp";
import ForgotPassword from "./views/User/ForgotPassword";
import ResetPassword from "./views/User/ResetPassword";
const hist = createBrowserHistory();
ReactDOM.render(
<Router history={hist}>
<Route path="/signup" component={Signup} />
<Route path="/login" component={Login} />
<Route path="/forgot-password" component={ForgotPassword} />
<Route path="/rest-auth/password/reset/confirm/:uidb64([0-9A-Za-z_\-]+)/:token([0-9A-Za-z]{1,20}-[0-9A-Za-z]{1,50})" component={ResetPassword}/
<Redirect from="/" to="/login" />
</Router>,
document.getElementById("root")
);
Here any url i open in browser it gets redirected to /login
eg: I open /signup it gets redirected to /login
the link works but when i open any url in the browser it gets redirected to /login
I found the reason is not using switch. If i use switch it worked
import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import { Router, Route, Switch, Redirect } from "react-router-dom";
import Login from "./views/User/Login";
import Signup from "./views/User/SignUp";
import ForgotPassword from "./views/User/ForgotPassword";
import ResetPassword from "./views/User/ResetPassword";
const hist = createBrowserHistory();
ReactDOM.render(
<Router history={hist}>
<Switch>
<Route path="/signup" component={Signup} />
<Route path="/login" component={Login} />
<Route path="/forgot-password" component={ForgotPassword} />
<Route path="/rest-auth/password/reset/confirm/:uidb64([0-9A-Za-z_\-]+)/:token([0-9A-Za-z]{1,20}-[0-9A-Za-z]{1,50})" component={ResetPassword}/
<Redirect from="/" to="/login" />
</Switch>
</Router>,
document.getElementById("root")
);
Also Route and Redirect should be directly below the Switch else Switch will not work.
Example
<Router history={hist}>
<Switch>
<>
<Route path="/signup" component={Signup} />
<Route path="/login" component={Login} />
<Route path="/forgot-password" component={ForgotPassword} />
<Route path="/rest-auth/password/reset/confirm/:uidb64([0-9A-Za-z_\-]+)/:token([0-9A-Za-z]{1,20}-[0-9A-Za-z]{1,50})" component={ResetPassword}/
<Redirect from="/" to="/login" />
</>
</Switch>
</Router>,
Switch does not have any affect here, so if we try to enter in browser /signup it also matches / so it goes to /login

React-Router how to prevent from redirect

So I have a problem in my code that when I refresh my page it sends me a NotFound page, but when I don't refresh the page still works while changing the route (single page application)
My routes code:
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Navigation from './src/containers/Navigation/Navigation';
import PageProjects from './src/containers/PageProjects/PageProjects';
import NewPost from './src/components/pages/Projects/NewPost/NewPost'
import Home from './src/components/pages/Home/Home';
import Calendar from './src/components/pages/Calendar/Calendar';
import Team from './src/components/pages/Team/Team';
import Settings from './src/components/pages/Settings/Settings';
import NotFound from './src/components/pages/NotFound/NotFound';
class App extends Component {
render() {
return (
<div className="App" style={{ height: '100%' }}>
<BrowserRouter>
<div>
<Navigation />
<Switch>
<Route path="/profile" component={Home} exact />
<Route path="/projects" component={PageProjects} exact />
<Route path="/calendar" component={Calendar} exact />
<Route path="/team" component={Team} exact />
<Route path="/newpost" component={NewPost} exact />
<Route path="/settings" component={Settings} exact />
<Route path="*" component={NotFound} exact />
</Switch>
</div>
</BrowserRouter>
</div>
);
}
}
export default App;
Only my "/profile" page works because it's the page that I'm sending the index.html file from my route server
app.get('/profile', function(req, res){
res.sendFile(__basedir + "/react/index.html");
});
My Navigation Component:
import React, { Component } from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import Toolbar from '../../components/Toolbar/Toolbar';
import SideBar from '../../components/SideBar/SideBar';
import Backdrop from '../../components/Backdrop/Backdrop';
import Home from '../../components/pages/Home/Home';
import Calendar from '../../components/pages/Calendar/Calendar';
import Team from '../../components/pages/Team/Team';
import Settings from '../../components/pages/Settings/Settings';
import NotFound from '../../components/pages/NotFound/NotFound';
class Navigation extends Component {
state = {
sideBarOpen: false,
}
barToggleClickHandler = () => {
this.setState((prevState) => {
return{sideBarOpen: !prevState.sideBarOpen};
});
};
backdropClickHandler = () => {
this.setState({sideBarOpen: false});
};
render() {
let backdrop;
if(this.state.sideBarOpen){
backdrop = <Backdrop click={this.backdropClickHandler}/>;
}
return (
<section className="Navigation">
<Toolbar barClickHandler={this.barToggleClickHandler} />
<SideBar show={this.state.sideBarOpen}/>
{backdrop}
<main style={{marginTop: '150px'}}>
</main>
</section>
);
}
}
export default Navigation;
What can I do?
Thanks
(I'm using Reactjs, Nodejs, Express..)
app.get('/', function(req, res){
res.sendFile(__basedir + "/react/index.html");
});
or use hashrouter
<HashRouter>
<div>
<Navigation />
<Switch>
<Route path="/profile" component={Home} exact />
<Route path="/projects" component={PageProjects} exact />
<Route path="/calendar" component={Calendar} exact />
<Route path="/team" component={Team} exact />
<Route path="/newpost" component={NewPost} exact />
<Route path="/settings" component={Settings} exact />
<Route path="*" component={NotFound} exact />
</Switch>
</div>
</HashRouter>
This should do the trick !
app.get('/', function(req, res){
res.sendFile(__basedir + "/react/index.html");
});

Resources