React-Router-DOM: unable to render Link in the same page (component) - javascript

consider the following example, I have a login page and an admin page. After logging in we will be redirected to admin page.
The admin page is shown as follows.
Desired behaviour: To render cars component in the admin component itself
Actual behaviour: On clicking cars or bikes component they are being rendered on a different page.
code is as follows
App.js
//imports here
function App() {
return(
<Router>
<Switch>
<Route exact path="/" component={Login} />
<Route exact path="/admin" component={Admin} />
<Route exact path="/cars" component={Cars} />
<Route exact path="/bikes" component={Bikes} />
</Switch>
</Router>
);
}
Admin.js
//imports here
const Admin = () => {
return (
<Fragment>
<div className="is-flex">
<Sidebar />
<Navbar />
</div>
</Fragment>
);
};
navbar.js
// imports here
const Sidebar = () => {
return (
<aside className="aside">
<p className="menu-label">Test Routes</p>
<ul className="menu-list">
<li>
<Link to="/cars">Cars</Link>
</li>
<li>
<Link to="/bikes">Bikes</Link>
</li>
</ul>
</aside>
);
};
Using react-router-dom ^5.1.2
Tried this but not able to understand what I missed? how to solve this problem?

Move your default route to the bottom of the stack. i.e.
function App() {
return(
<Router>
<Switch>
<Route path="/admin" component={Admin} />
<Route path="/cars" component={Cars} />
<Route path="/bikes" component={Bikes} />
<Route exact path="/" component={Login} />
</Switch>
</Router>
);
}

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

common header issue in react js

I have problem with common header in react js.
Currently login route is displaying common header and i dont want to show on my login page. If i go to contacts page than its showing common header which is perfect
import "./styles/App.scss";
import Navbar from "./components/elements/Navbar";
import Contacts from "./components/contacts/Contacts";
import { Provider } from "react-redux";
import store from "./store";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import AddContact from "./components/contacts/AddContact";
import EditContact from "./components/contacts/EditContact";
import Login from "./components/login/Login";
import Logout from "./components/logout/Logout";
function App(props) {
return (
<Provider store={ store }>
<Router>
<div className="App">
{props.location.pathname !== '/login' ? <Navbar/> : null}
<Route exact path="/login" component={ Login } />
<div className="container">
<div className="py-3">
<Switch>
<Route exact path="/" component={ Contacts } />
<Route exact path="/logout" component={ Logout } />
<Route exact path="/contacts/add" component={ AddContact } />
<Route
exact
path="/contacts/edit/:id"
component={ EditContact }
/>
</Switch>
</div>
</div>
</div>
</Router>
</Provider>
);
}
export default App;
[1]: https://i.stack.imgur.com/7V0qi.png
I think you meant to create Links in NavBar, not declare the Routes:
<Router>
<div className="App">
<div className="container">
<div className="py-3">
<Switch>
<Route exact path="/login" component={Login} />
<Route>
<Navbar />
<Switch>
<PrivateRoute exact path="/" component={Contacts} />
<PrivateRoute exact path="/logout" component={Logout} />
<PrivateRoute exact path="/contacts/add" component={AddContact} />
<PrivateRoute
exact
path="/contacts/edit/:id"
component={EditContact}
/>
</Switch>
</Route>
</Switch>
</div>
</div>
</div>
</Router>
NavBar:
function Navbar() {
const someId = 123 // example
return (
<>
<Link to="/">Login</Link>
<Link to="/logout">Logout</Link>
<Link to="/contacts/add">Add Contacts</Link>
<Link to={`/contacts/edit/${someId}`}>Edit Contact</Link>
</>
)
}
After this, you are most likely to be looking for authentication. I recently wrote an answer on authenticated or protected routes i.e. PrivateRoute.
Also, note that All children of a Switch should be Route or Redirect elements.
You can only show the <Navbar/> when it's not the login page and you need to keep the login page inside the switch for the pages to work.
return (
<Provider store={ store }>
<Router>
<div className="App">
{props.location.pathname !== '/login' ? <Navbar/> : null}
<div className="container">
<div className="py-3">
<Switch>
<Route exact path="/login" component={ Login } />
<Route exact path="/" component={ Contacts } />
<Route exact path="/logout" component={ Logout } />
<Route exact path="/contacts/add" component={ AddContact } />
<Route
exact
path="/contacts/edit/:id"
component={ EditContact }
/>
</Switch>
</div>
</div>
</div>
</Router>
</Provider>
);

ReactJS Routing Page Refresh

Currently using ReactJS to construct a small web app. I have the following parent function:
const Main = () => {
return (
<div className="dialog-base">
<BrowserRouter>
<Switch>
<Route exact path="/login" component={Login}></Route>
<Route exact path="/login/forgot_password" component={ForgotPwd}></Route>
<Route exact path="/login/reset_password/:key" component={ResetPwd}></Route>
<Route exact path="/portal" component={Portal}></Route>
</Switch>
</BrowserRouter>
</div>
);
}
and the following is the "Portal" component:
class Portal extends React.Component {
render = () => {
return (
<BrowserRouter basename="/main">
<div className="navmenu">
<NavLink to="messaging" activeClassName="selected">Messaging</NavLink>
<NavLink to="files" activeClassName="selected"></NavLink>
<NavLink to="payledger" activeClassName="selected"></NavLink>
</div>
<div className="apparea">
<Switch>
<Route path="/messaging" component={Messaging}></Route>
<Route path="/files" component={Files}></Route>
<Route path="/payledger" component={PayLedger}></Route>
</Switch>
</div>
</BrowserRouter>
);
}
}
When the portal component is loaded and I refresh the web page, the page goes blank. I am assuming that this has something to do with the nested routing? Any help on how to fix it would be much appreciated.
You don't need two <BrowserRouter />. Just define one <BrowserRouter /> in your top level component.
In react-router-dom v4+ the <Route /> is just like a regular component and you can use it inside your components to render UI when the path matches the URL.
Here is the working codesandbox example.
Make sure not to put exact on your parent <Route /> because when you have child routes like /main/messaging the <Route exact path="/main" /> never gets to render and therefore children of that route can't be rendered also.
You keep your <Main /> component as is but remove the exact from the <Route path='/portal' /> and change the <Portal />.
class Portal extends React.Component {
render = () => {
return (
<React.Fragment>
<div className="navmenu">
<NavLink to="/portal/messaging" activeClassName="selected">Messaging</NavLink>
<NavLink to="/portal/files" activeClassName="selected"></NavLink>
<NavLink to="/portal/payledger" activeClassName="selected"></NavLink>
</div>
<div className="apparea">
<Switch>
<Route path="/portal/messaging" component={Messaging}></Route>
<Route path="/portal/files" component={Files}></Route>
<Route path="/portal/payledger" component={PayLedger}></Route>
</Switch>
</div>
</React.Fragment>
);
}
}

Render components under root route not working as expected

I have a route path / that rendering Home component
Home component contain a list. every item should render a route /:id
So much paths will be www.example/:id
I would render lists content under home content.
My problem is that every time I click on a list item the list get disappeared and nothing is rendered.
function Home() {
return (
<div>
<h1>Topics</h1>
<ul>
{topics.map(({ name, id }) => (
<li key={id}>
<Link to={`/${id}`}>{name}</Link>
</li>
))}
</ul>
<hr />
<Route path={`/:topicId`} component={Topic} />
</div>
);
}
function Topic() {
return <div>TOPIC</div>;
}
class App extends React.Component {
render() {
return (
<Router>
<Route exact path="/" component={Home} />
</Router>
);
}
}
export default App;
Here's an example
For this kind of similar routes. we will deal with exact props. No need to reorder the routes.
<Switch>
<Route exact path="/" component={Home} />
<Route path="/:topicId" component={Topic} />
<Switch>
For more details, you can follow https://reactrouter.com/web/api/Route/exact-bool
You should remove the exact, like so:
<Router>
<Route path="/" component={Home} />
<Route path="/:topicId" component={Topic} />
</Router>
Now your Home & Topic will appear

Unable to render react components upon clicking the Links

I have a react application in which I have wrapped layout components for the other routes, the thing is when I click the links present in the sidebar(part of layout) they are not being rendered on the screen, here is my code.
App.js
//Imports here
<Provider store={store}>
<Router>
<Switch>
<Layout>
<Route exact path="/admin" render={() => <Admin />} />
<Route exact path="/employees" render={() => <Employees />} />
<Route exact path="/profile" component={Profile} />
</Layout>
<Switch>
</Router>
</Provider>
Layout.js
//imports here
//styling here
<Link to='/employees' />
// and likewise for rest of the routes
When clicking the links ie, employees or profile they aren't being rendered, tried console.log to see if my layout was obstructing that, but no use. Please help me
It should be inside the Switch component but you can wrap it with a Layout component like that.
const Headers = () => (
<Layout>
<ul>
<li>
<Link to="/admin">Admin</Link>
</li>
<li>
<Link to="/profile">Profile</Link>
</li>
<li>
<Link to="/employees">Employees</Link>
</li>
</ul>
</Layout>
);
function App() {
return (
<Router>
<Layout>
<Header></Header>
<Switch>
<Route exact path="/admin" render={() => <Admin />} />
<Route exact path="/employees" render={() => <Employees/>}/>
<Route exact path="/profile" component={Profile} />
</Switch>
</Layout>
</Router>
);
}
If your URL is changing but the content is not being rendered, the problem is this, apart from wrapping the Routes as mentioned in #G.aziz 's answer since the routes are children WRT layout components we have to use {props.children} inside the layout component to render the content like so...
Layout.jsx
<div>
<Sidebar />
<Navbar />
{props.children} // here we are rendering the routes which we mentioned in the switch component in App.js
</div>
For me this solution fixed. Also please refer this question for further information. React-router v4, URL changing but component doesn't render

Categories

Resources