React-Router how to prevent from redirect - node.js

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");
});

Related

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>

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}</>;
}

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 />} />

react-router-dom cannot render page [duplicate]

I am building a Netflix clone application, and I am using react-router-dom v5 to switch between different pages. However, when I click the Link tag in Navbar.jsx, the URL changes, but the corresponding component doesn't render. I have consulted numerous StackOverflow posts on this topic, however, I can't get it to work. Below is the code. Please help me, as I'm stuck on this for 3 days 😥.
What it should show, when navigating to /series from /:
What it is actually showing:
index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.jsx
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "./app.scss";
import Home from "./pages/home/Home";
import Watch from "./pages/watch/Watch";
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/movies">
<Home type="movies" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</Switch>
</Router>
);
};
export default App;
Home.jsx
import React from "react";
import Featured from "../../components/featured/Featured";
import Navbar from "../../components/navbar/Navbar";
import "./home.scss";
const Home = ({ type }) => {
return (
<div className="home">
<Navbar />
<Featured type={type} />
</div>
);
};
export default Home;
Navbar.jsx
import React, { useState } from "react";
import "./navbar.scss";
import { Link } from "react-router-dom";
const Navbar = () => {
const [isScrolled, setIsScrolled] = useState(false);
window.onscroll = () => {
setIsScrolled(window.scrollY === 0 ? false : true);
return () => window.onscroll == null;
};
return (
<div className={`navbar ${isScrolled ? "scrolled" : ""}`}>
<div className="container">
<img src="./netflix_logo.jpg"
alt="netflix logo"
/>
<Link to="/" className="link">
<span>Home</span>
</Link>
<Link to="/series" className="link">
<span>Series</span>
</Link>
<Link to="/movies" className="link">
<span>Movies</span>
</Link>
<Link to="" className="link">
<span>New and Popular</span>
</Link>
<Link to="" className="link">
<span>My List</span>
</Link>
</div>
</div>
);
};
export default Navbar;
Featured.jsx
import "./featured.scss";
import { IoMdPlay } from "react-icons/io";
import { FiInfo } from "react-icons/fi";
const Featured = ({ type }) => {
return (
<div className="featured">
{type && (
<div className="category">
<span style={{ color: "white" }}>
{type === "movies" ? "Movies" : "TV Series"}
</span>
<select name="genre" id="genre">
<option>Genre</option>
<option value="adventure">Adventure</option>
<option value="comedy">Comedy</option>
<option value="crime">Crime</option>
<option value="fantasy">Fantasy</option>
<option value="historical">Historical</option>
<option value="horror">Horror</option>
<option value="romance">Romance</option>
<option value="sci-fi">Sci-fi</option>
<option value="thriller">Thriller</option>
<option value="western">Western</option>
<option value="animation">Animation</option>
<option value="drama">Drama</option>
<option value="documentary">Documentary</option>
</select>
</div>
)}
<img
src="https://m.media-amazon.com/images/M/MV5BNzM4OTkzMjcxOF5BMl5BanBnXkFtZTgwMTkxMjI1MTI#._V1_.jpg"
alt="featured"
/>
<div className="info">
<img
src="https://occ-0-1432-1433.1.nflxso.net/dnm/api/v6/LmEnxtiAuzezXBjYXPuDgfZ4zZQ/AAAABUZdeG1DrMstq-YKHZ-dA-cx2uQN_YbCYx7RABDk0y7F8ZK6nzgCz4bp5qJVgMizPbVpIvXrd4xMBQAuNe0xmuW2WjoeGMDn1cFO.webp?r=df1"
alt=""
/>
<span className="desc">
When a beautiful stranger leads computer hacker Neo to a forbidding
underworld, he discovers the shocking truth - the life he knows is the
elaborate deception of an evil cyber-intelligence.
</span>
<div className="buttons">
<button className="play">
<IoMdPlay className="button-logo" />
<span>Play</span>
</button>
<button className="more">
<FiInfo className="button-logo" />
<span>More Info</span>
</button>
</div>
</div>
</div>
);
};
export default Featured;
There's a compatibility issue between pre-5.3.3 versions of react-router-dom#5 and react#18.
Github Issue #7870
PR #8831 merged to address issue - Fix was merged on May 18th, 2022, react-router-dom v5.3.3.
Solutions
Bugfix was merged into v5.3.3. Update to react-router-dom#5.3.3 or higher.
From the project's root directory run:
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3 (or #latest)
Revert back to React 17 (or React 17 syntax) and fix up the index.js file.
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById("root")
);
Make the React.StrictMode component a child/descendent of the router component. Comment.
Replace:
<React.StrictMode>
...
<BrowserRouter>
...
</BrowserRouter>
</React.StrictMode>
with:
<BrowserRouter>
<React.StrictMode>
...
</React.StrictMode>
</BrowserRouter>
Upgrade to react-router-dom#6 and fix up the routes.
const App = () => {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movies" element={<Home type="movies" />} />
<Route path="/series" element={<Home type="series" />} />
<Route path="/watch" element={<Watch />} />
</Routes>
</Router>
);
}
First Solution and Best Solution:
If you use are using React Router 5.3.x, check whether it is 5.3.3 in your package.json file.
If it is not 5.3.3 uninstall the last version then install the bug-free version which has been resolved by John and updated in version 5.3.3.
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3
Second Solution:
React has launched its StrictMode in its latest update.
you can see it in an index.js file
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
So here your React Router is in the child component. And we have to make it a parent component.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
);
Third Solution:
Remove the Strict mode from the index.js file
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);

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

Resources