React Router and Link do not render - javascript

I'm working on a react app and I found my page does not render when the url changes. See the code below, I have a navigagtion bar with three Link, when I click them, I can see that the url changes in the address bar, but the page is still staying the one from the old url. However if I refresh the page, then the corresponding page to the current url is rendered and presented.
I saw a similar question but the method in it does not work for me, or maybe I use it in a wrong way? React Router or Link Not Rendered
this is the code from my App.js:
import {BrowserRouter, Switch, Route, Link} from 'react-router-dom';
import Home from './booking/Home';
import Login from './auth/Login';
import Register from './auth/Register';
const TopNav = () => (
<div className="nav bg-light d-flex justify-content-between">
<Link className="nav-link" to="/">
Home
</Link>
<Link className="nav-link" to="/login">
Login
</Link>
<Link className="nav-link" to="/register">
Register
</Link>
</div>
);
function App() {
return (
<BrowserRouter>
{TopNav()}
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
</Switch>
</BrowserRouter>
);
}
export default App;

What is your React Router version? If it's React Router v6. You need to change it like this below:
<Route exact path="/" element={<Home />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/register" element={<Register />} />
Because using component is from React Router v5, the newest version using element
Hope it helps!

Could you try to use JSX for your TopNav component?
return (
<BrowserRouter>
<TopNav/>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
</Switch>
</BrowserRouter>
);
}
Also put react in scope for your app at the top
import React from 'react';
import {BrowserRouter, Switch, Route, Link} from 'react-router-dom';
import Home from './Home';
import Login from './Login';
import Register from './Register';
import React from 'react';
const TopNav = () => (
<div className="nav bg-light d-flex justify-content-between">
<Link className="nav-link" to="/">
Home
</Link>
<Link className="nav-link" to="/login">
Login
</Link>
<Link className="nav-link" to="/register">
Register
</Link>
</div>
);
function App() {
return (
<BrowserRouter forceRefresh>
<TopNav />
<Switch>
<Route exact path="/register" component={Register} />
<Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
</Switch>
</BrowserRouter>
);
}
export default App;

Related

How to make React nested routes v6 work to display app components?

Hello Stackoverflow community
I am building a simple SPA using react. My navigation for the app would be a unauthenticated public page(like home/about/pricing etc) and a sign in button that the user will click on to be redirected into the app components after authentication using keycloak.
The way I have structured the app is having a parent router that will redirection between public facing files and then another router that will help router inside the app. The problem I am facing is my app router works but no HTML is displayed or no components are displayed (dashboard component not displayed)
My app.js file
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import HomePage from "./pages/Homepage";
import AboutPage from "./pages/AboutPage";
import SecuredPage from "./pages/Securedpage";
import PricingPage from "./pages/PricingPage";
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route exact path="/" element={<HomePage />} />
<Route path="/about" element={ <AboutPage />} />
<Route path="/pricing" element={ <PricingPage />} />
<Route exact path="/app" element={ <SecuredPage />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
My HomePage.JS contains
import React from 'react';
import NavMain from "../components/NavMain";
const Home = () => {
return (
<div>
<NavMain/>
<h1 className="text-green-800 text-4xl">Welcome to the Homepage. Some more text123</h1>
</div>
);
};
export default Home;
My NavMain.JS contains
<ul>
<li>
<a href="/">
Home
</a>
</li>
<li>
<a href="/about">
About
</a>
</li>
<a href="/pricing">
pricing
</a>
</li>
<li>
<a href="/app/dashboard">
app
</a>
</li>
</ul>
The public facing components work correctly. Once I click on 'app' I am redirected to the keycloak authentication page and from there after login I am on the securepage page component. But it does not render the dashboard component
SecuragePage.js
import React from 'react';
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { ReactKeycloakProvider } from "#react-keycloak/web";
import keycloak from "../Keycloak";
import Dashboard from "./Dashboardpage";
import AboutPage from "./AboutPage";
import PrivateRoutes from "../helpers/PrivateRoutes";
import NavHomePage from "../components/NavHomePage";
const Loading = () => <div>Loading...</div>
const Secured = () => {
return (
<div>
<ReactKeycloakProvider authClient={keycloak}
initOptions={{
onLoad: "login-required",
}}
LoadingComponent={<Loading />} >
app landing page
<NavHomePage/>
<Routes>
<Route element={<PrivateRoutes />}>
<Route exact path="/app/dashboard" element={ <Dashboard />} />
</Route>
</Routes>
</ReactKeycloakProvider>
</div>
);
};
export default Secured;
Dashboard.js
import React from 'react';
const Dashboard = () => {
return (
<div>
<h1 className="text-green-800 text-4xl">Dashboard</h1>
</div>
);
};
export default Dashboard;
NavHomePage.js
<Navbar bg="dark" variant="dark">
<Container>
<Navbar.Brand href="/">Hype</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link href="/app">Home</Nav.Link>
<Nav.Link href="/app/dashboard">dashboard</Nav.Link>
</Nav>
<Nav className="ml-auto">
{!!keycloak.authenticated && (
<Nav.Link onClick={() => logoutHelper()}>
Logout ({keycloak.tokenParsed.preferred_username})</Nav.Link>)}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
PrivateRouters.js
const PrivateRoutes = () => {
const { keycloak } = useKeycloak();
const isLoggedIn = keycloak.authenticated;
console.log("checking auth access " + isLoggedIn);
console.log(keycloak);
return isLoggedIn ? <Outlet/> : null;
};
Try to use
import { Link } from "react-router-dom";
Instead of using or <Nav.Link>.
You can easily wrap these inside of
<Link to='/app'><Nav.Link>Home</Nav.Link></Link>
Check example here: https://reactrouter.com/en/main/components/link
The SecuredPage component is rendering descendent routes, so the parent route must append a wildcard "*" route matcher to it's route so descendent routes can be matched and rendered.
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/pricing" element={<PricingPage />} />
<Route path="/app/*" element={<SecuredPage />} /> // <-- append "*" to path
</Routes>
</BrowserRouter>
</div>
);
}
Descendent Routes components also build their paths relative to any parent Routes components, so the descendent path should not include any of the "path prefix" to this Routes.
const Secured = () => {
return (
<div>
<ReactKeycloakProvider
authClient={keycloak}
initOptions={{
onLoad: "login-required",
}}
LoadingComponent={<Loading />}
>
app landing page
<NavHomePage/>
<Routes>
<Route element={<PrivateRoutes />}>
<Route path="dashboard" element={<Dashboard />} />
</Route>
</Routes>
</ReactKeycloakProvider>
</div>
);
};
If you didn't want to use descendent routes you could convert Secured into a layout route component.
Example:
import { Outlet } from 'react-router-dom';
const KeycloakLayout = () => {
return (
<div>
<ReactKeycloakProvider
authClient={keycloak}
initOptions={{
onLoad: "login-required",
}}
LoadingComponent={<Loading />}
>
<NavHomePage/>
<Outlet />
</ReactKeycloakProvider>
</div>
);
};
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/pricing" element={<PricingPage />} />
<Route path="/app" element={<KeycloakLayout />}>
<Route element={<PrivateRoutes />}>
<Route path="dashboard" element={<Dashboard />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
</div>
);
}
No idea why it doesn't work for you, there should be an example that can be debugged. Learn from this youtube-channel how a good example works:
Youtube tutorial keycloak with react
Nevertheless, I see some things in your code that shouldn't be done like this anymore:
Do not use the react-keycloak/web library. It has not been serviced since 2021 and is no longer needed!
Check out the youtube links for a good example of keycloak authentication with routing without this react library.
Don't use <divs> in your code unless absolutely necessary. If you need divs, then use the <React.Fragments /> or <></> for short. Why is that important? If you want to debug your project in a browser in the future, these divs make the code very cluttered and tedious to debug.
For example here:
const Home = () => {
return (
<> //NO <div> USED
<NavMain/>
<h1 className="text-green-800 text-4xl">Welcome to the Homepage. Some more text123</h1>
</>
);
};
Another code:
function App() {
return (
//DONT USE DIV HERE. USELESSS
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/pricing" element={<PricingPage />} />
<Route path="/app" element={<KeycloakLayout />}>
<Route element={<PrivateRoutes />}>
<Route path="dashboard" element={<Dashboard />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
);
}

React Routing V6 problem, redirecting to another path: '/contact' the content from <Contact /> get updated above nav instead of separate page

I am trying to make Airbnb Clone using React 18, but above nav something like this is happening:
I am using React BrowserRouter V6, whenever we redirect to another page like localhost:3000/about, the about page should open instead of the whole page rendering on all the paths:
App.js:
import './App.css';
import Title from './Components/Title.js'
import Tagline from './Components/Tagline.js'
import Navbar from './Components/Navbar.js'
import Firstpara from './Components/Firstpara.js'
import Card from './Components/Card.js'
import React, { Components } from 'react'
export default function App() {
return (
<div className="App">
<div className="header">
<Title />
<Tagline />
<Navbar />
</div>
<Firstpara />
<Card />
{/* <Contact/> */}
</div>
);
}
Navbar.js:
import React from 'react';
import { Link, BrowserRouter as Router, Route, Routes } from "react-router-dom";
import About from "../Pages/About"
import Contact from "../Pages/Contact"
import Features from "../Pages/Features"
import Error from '../Pages/Error'
export default function Navbar() {
return (
<>
<div className="navbar container-fluid">
<Router>
<Routes>
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/features" element={<Features />} />
<Route path="*" element={<Error />} />
</Routes>
<div id="right-menu">
<ul className="navbar-nav">
<li>Visit</li>
<li><Link to="/about">About</Link></li>
<li><Link to="/features">Features</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</div>
</Router>
</div>
</>
)
}
In your app.js file change your code to this (this is just for a demo) you change it as your requirements
import { BrowserRouter,Routes,Route,} from "react-router-dom";
import Navbar from "./components/navbar/Navbar";
import Register from "./components/auth/Register";
import Login from "./components/auth/Login";
return (
<>
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/" index element={<Home />} />
<Route path="/login" element={<Login />}/>
<Route path="/register" element={<Login />}/>
<Routes/>
</BrowserRouter>
</>
);
I think the issue you have is that the Navbar is rendering all the routing code, the router, routes, and the links. Then additionally it is rendering the routes above the links.
Move the Router and routes out to the App. The Router should wrap the Navbar and routes, and the routes should be rendered below the Navbar/header.
Example:
App
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
export default function App() {
return (
<Router>
<div className="App">
<div className="header">
<Title />
<Tagline />
<Navbar />
</div>
<Routes>
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/features" element={<Features />} />
<Route path="*" element={<Error />} />
</Routes>
<Firstpara />
<Card />
{/* <Contact/> */}
</div>
</Router>
);
}
Navbar
import { Link } from "react-router-dom";
export default function Navbar() {
return (
<div className="navbar container-fluid">
<div id="right-menu">
<ul className="navbar-nav">
<li>Visit</li>
<li><Link to="/about">About</Link></li>
<li><Link to="/features">Features</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</div>
</div>
);
}

Blank page is displayed instead of Bootstrap Navbar that I am trying to create with React Router

I am trying to create a navbar using Bootstrap and React. Even though my code is compiled without any errors the webpage that is rendered is completely blank. Please see my code below for reference:
app.js:
import React, { Component } from "react";
import { useState } from "react";
import logo from "./logo.svg";
import { Routes, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import AddReview from "./components/add-review";
import RestaurantlLst from "./components/restaurant-list";
import Restaurants from "./components/restaurants";
import Login from "./components/login";
function App() {
const [user, setUser] = useState(null);
async function login(user = null) {
setUser(user);
}
async function logout() {
setUser(null);
}
return (
<div>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">
Restaurant Reviews
</a>
<div class="navbar-nav mr-auto">
<li class="nav-item">
<Link to={"/restaurants"}>Restaurants</Link>
</li>
<li class="nav-item">
{user ? (
<a
onClick={logout}
className="nav-link"
style={{ cursor: "pointer" }}
>
Logout {user.name}
</a>
) : (
<Link to={"/login"} className="nav-link">
Login
</Link>
)}
</li>
</div>
</nav>
<div className="container mt-3">
<Routes>
<Route
exact
path={["/", "/restaurants"]}
component={RestaurantlLst}
/>
<Route
path="/restaurants/:id/review"
render={(props) => <AddReview {...props} user={user} />}
/>
<Route
path="/restaurants/:id"
render={(props) => <Restaurants {...props} user={user} />}
/>
<Route
path="/login"
render={(props) => <Login {...props} user={user} />}
/>
</Routes>
</div>
</div>
);
}
export default App;
index.js:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
All of the components are similar, as given below:
Login component:
import React from "react";
function Login() {
return <div>Login</div>;
}
export default Login;
What am I doing wrong ?
The Route component API changed in v6, there isn't any component or render prop now, they were replaced by a single element prop taking a ReactNode, a.k.a. JSX. The path prop now also only takes a single path string, not an array.
<Routes>
<Route
path="/"
element={<RestaurantlLst />}
/>
<Route
path="/restaurants"
element={<RestaurantlLst />}
/>
<Route
path="/restaurants/:id/review"
element={<AddReview user={user} />}
/>
<Route
path="/restaurants/:id"
element={<Restaurants user={user} />}
/>
<Route
path="/login"
render={<Login user={user} />}
/>
</Routes>
If these components need to access "route props" these also no longer exist. They should use the React hooks that replaced them if they need to access location, params, etc.
Another way to structure the routes is to use layout and index routes:
Example:
<Routes>
<Route path="/">
<Route index element={<Navigate to="restaurants" replace />} />
<Route path="restaurants">
<Route index element={<RestaurantlLst />} />
<Route path=":id">
<Route index element={<Restaurants user={user} />} />
<Route path="review" element={<AddReview user={user} />} />
</Route>
</Route>
</Route>
<Route
path="/login"
render={<Login user={user} />}
/>
</Routes>

React Router with other components

I have one problem that I can not understand. I am totally a beginner in ReactJS so I hope you will help me. I made Navigation with React Router and it works, but when I start to render all other components in App.js nothings happened. When I am routing through the navigation bar it is rendering, but on scroll, nothing happened.
This is my App.js without rendering other components that work normally, but when I add something like , it is the same without scroll.
my code :
const App = () => {
return (
<div>
<Router>
<Topbar />
<About />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/service" component={Service} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact} />
</Switch>
</Router>
</div>
);
};
export default App;
You need to use a redirect
1/ import {Redirect} from 'react-router-dom';
2/ Change your Home route to <Route exact path="/home" component={Home} />
3/ Add the redirect (It must be the last route)
<Route exact path="/">
<Redirect to="/home" />
</Route>
Example :
import React from 'react';
import {
BrowserRouter as Router,
Route,
Switch,
Redirect
} from 'react-router-dom';
import Home from './Home';
import About from './About';
import Service from './Service';
import Portfolio from './Portfolio';
import Contact from './Contact';
const App = () => {
return (
<Router>
<Switch>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/service" component={Service} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact} />
{/* Redirect */}
<Route exact path="/">
<Redirect to="/home" />
</Route>
</Switch>
</Router>
);
};
export default App;
If you want to check a demo : Stackblitz

Can't show Error 404 Component in nested Component in React Router

I'm trying show Error component if matches not found, but nothing happens - when I choose non-existing route, I see only blank page.
The Main component adds sidebar menu in example and renders all it childes inside in rest.
When all Route componets placed directly inside Switch - all works (including Error).
But in example below, Error component does not render - if route does not match - only blank page.
If Error component placed inside Main, in that case it will be rendered even for existing routes.
import React from 'react';
import { Switch, Route } from "react-router-dom";
import Signin from "../../containers/Signin";
import Signup from "../../containers/Signup";
import Error from "../../containers/Error";
import Courses from "../../containers/Courses";
import Course from "../../containers/Course";
import Quiz from "../../containers/Quiz";
import Header from "../Header";
import "./App.css";
import Library from "../../containers/Library";
import QuizResults from "../../containers/QuizResults";
import Main from "../Main";
import StudentsList from "../../containers/StudentsList";
function App()
{
return (
<div className="App">
<Header isLogged={false}/>
<Switch>
<Route exact path='/' component={Signin} />
<Route path='/signup' component={Signup} />
<Main>
<Route path='/courses' component={Courses} />
<Route path='/course/:id' component={Course} exact/>
<Route path='/quiz' component={Quiz} />
<Route path='/library' component={Library} />
<Route path='/quiz-results' component={QuizResults} />
<Route path='/students' component={StudentsList} />
<Route component={Error} />
</Main>
</Switch>
</div>
);
}
export default App;
So, how to properly render Error component if no matches found?
Try using a wildcard.
<Route path="/*" component={Error} />
Add exact word to the route. And better approach will be to set the Error component name to NotFound or FourZeroFour . It will work then.
<Router>
<Switch>
<Route exact path='/' component={Signin} />
<Route exact path='/signup' component={Signup} />
<Main>
<Route exact path='/courses' component={Courses} />
<Route exact path='/course/:id' component={Course} />
<Route exact path='/quiz' component={Quiz} />
<Route exact path='/library' component={Library} />
<Route exact path='/quiz-results' component={QuizResults} />
<Route exact path='/students' component={StudentsList} />
<Route component={NotFound} />
</Main>
</Switch>
</Router>
Solution for this problem - place another Switch around Route components:
import React from 'react';
import { Switch, Route } from "react-router-dom";
import Signin from "../../containers/Signin";
import Signup from "../../containers/Signup";
import NotFound from "../../containers/NotFound";
import Courses from "../../containers/Courses";
import Course from "../../containers/Course";
import Quiz from "../../containers/Quiz";
import Header from "../Header";
import "./App.css";
import Library from "../../containers/Library";
import QuizResults from "../../containers/QuizResults";
import Main from "../Main";
import StudentsList from "../../containers/StudentsList";
function App()
{
return (
<div className="App">
<Header isLogged={false}/>
<Switch>
<Route exact path='/' component={Signin} />
<Route exact path='/signup' component={Signup} />
<Main>
<Switch>
<Route exact path='/courses' component={Courses} />
<Route exact path='/course/:id' component={Course} />
<Route exact path='/quiz' component={Quiz} />
<Route exact path='/library' component={Library} />
<Route exact path='/quiz-results' component={QuizResults} />
<Route exact path='/students' component={StudentsList} />
<Route path='*' component={NotFound} />
</Switch>
</Main>
</Switch>
</div>
);
}
export default App;

Categories

Resources