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>
);
Related
I'm trying to upgrade to react-router-dom v6 :
v5
In version 5 it works like a charm:
App.js
import Sidebar from "./components/sidebar/Sidebar";
import Topbar from "./components/topbar/Topbar";
import "./app.css";
import Home from "./pages/home/Home";
import {
BrowserRouter as Router,
Switch,
Route,
} from "react-router-dom";
import UserList from "./pages/userList/UserList";
import User from "./pages/user/User";
import NewUser from "./pages/newUser/NewUser";
import ProductList from "./pages/productList/ProductList";
import Product from "./pages/product/Product";
import NewProduct from "./pages/newProduct/NewProduct";
import Login from "./pages/login/Login";
function App() {
const admin = JSON.parse(JSON.parse(localStorage.getItem("persist:root"))?.user || "{}")?.currentUser?.isAdmin ;
return (
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
{admin && (
<>
<Topbar />
<div className="container">
<Sidebar />
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<UserList />
</Route>
<Route path="/user/:userId">
<User />
</Route>
<Route path="/newUser">
<NewUser />
</Route>
<Route path="/products">
<ProductList />
</Route>
<Route path="/product/:productId">
<Product />
</Route>
<Route path="/newproduct">
<NewProduct />
</Route>
</div>
</>
)}
</Switch>
</Router>
);
}
export default App;
v6
When upgraded to v6 I changed my code to be like this:
<Routes>
<Route path="/login" element={<Login />} />
{admin && (
<>
<Route path="/" element={<Topbar />}/>
<Route path="/" element={
<>
<div className="container">
<Route index element={<Sidebar/>}/>
<Route index element={<Home/>}/>
<Route path="/users" element={<UserList />} />
<Route path="/user/:userId" element={<User />} />
<Route path="/newUser" element={<NewUser />} />
<Route path="/productList" element={<ProductList />} />
<Route path="/product/:productId" element={<Product />} />
<Route path="/newProduct" element={<NewProduct />} />
</div>
</>
}
</>
)}
</Routes>
This is my css file for App.js
Notice: the Topbar component should be outside the div, and react router didn't recognize the components inside the as routes even without div, that means each component should have a unique path, I tried also two components with the same path like this:
<Route path="/" element = {<><Home/><Sidebar/><>}, but the css is not taking effect
.container {
display: flex;
margin-top: 50px;
}
It doesn't work. I tried different code and I searched a lot without finding any solution.
Part of the issue is that you are rendering multiple identical paths, i.e. two "/" paths and two nested index paths. This won't work.
In react-router-dom v6 you can create what are called layout components. The layout components can render your headers and footers, sidebars, drawers, and general content layout elements, and importantly an Outlet component for the nested/wrapped Route components to be rendered into.
Example:
import { Outlet } from 'react-router-dom';
const AppLayout = ({ admin }) => admin ? (
<>
<Topbar />
<div className="container">
<Sidebar />
<Outlet />
</div>
</>
) : null;
Render the layout component into a Route wrapping the routes you want to be rendered into the specific layout.
<Routes>
<Route path="/login" element={<Login/>} />
<Route element={<AppLayout admin={admin} />}>
<Route index element={<Home />} />
<Route path="/users" element={<UserList />} />
<Route path="/user/:userId" element={<User />} />
<Route path="/newUser" element={<NewUser />} />
<Route path="/productList" element={<ProductList />} />
<Route path="/product/:productId" element={<Product />} />
<Route path="/newProduct" element={<NewProduct />} />
</Route>
</Routes>
I will share working code from my project, hope this will help you.
Try to create a component layout that should look something like this:
// Layout.js
import React from "react";
import { NavBar } from "./SidebarNav";
export const Layout = ({ children }) => {
return (
<>
<div className="block">
<NavBar />
<div className="w-full ">{children}</div>
</div>
</>
);
};
and then create routes in a similar way:
// routes.js
import { Routes, Route } from "react-router-dom";
import { Layout } from "./layout/Layout";
import Home from "./pages/Home";
import { ItemList } from "./pages/ItemList";
const BaseRouter = () => (
<>
<Layout>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/item-list/" element={<ItemList />} />
</Routes>
</Layout>
</>
);
export default BaseRouter;
Splitting routes into a separate file gives you more freedom and, above all, makes your code more accessible.
// App.js
import { BrowserRouter as Router } from "react-router-dom";
import BaseRouter from "./routes";
function App() {
return (
<Router>
<BaseRouter />
</Router>
);
}
export default App;
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
I am trying to access the FolderDetail component once the url /folders/xy is called. Instead of getting FolderDetail component I always get the Folders component which lies in /folders... Please help.
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<div className="App">
<Navigation />
<Switch>
<Route path="/" component={Home} exact />
<Route path="/folders" component={Folders} />
<Route path="/folders/:id" component={FolderDetail} />
<Route path="/login" component={Login} />
</Switch>
</div>
</BrowserRouter>
);
}
export default App;
You should add exact to all Routes components, this is a working codesandbox :
const App = () => {
return (
<BrowserRouter>
<div className="App">
<Navigation />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/folders" component={Folders} />
<Route exact path="/folders/:id" component={FolderDetail} />
</Switch>
</div>
</BrowserRouter>
);
};
A switch takes the firs matched route so you need to reorder your routes like this, (also add exact)
<Switch>
<Route exact path="/folders/:id" component={FolderDetail} />
<Route exact path="/folders" component={Folders} />
<Route exact path="/login" component={Login} />
<Route exact path="/" component={Home} exact />
</Switch>
Always put the more specific routes first.
I am trying to separate my routes depending on views. To be specific I have created an admin view where I am going to have different routes for admin only. I am trying to use multiple switches but I keep getting 404.
The following is how I am doing:
App.js
<div className="App">
<Switch>
<Route exact path="/admin/dashboard" component={ AdminPanel } />
<Route component={ NoMatch } />
</Switch>
</div>
AdminPanel.js
<Link to="/admin/dashboard" className="sidebar-item">...</Link>
<Link to="/admin/dashboard/exams" className="sidebar-item">...</Link>
.
.
.
<div className="admin-content">
<Switch>
<Route exact path="/admin/dashboard" component={ Dashboard } />
<Route exact path="/admin/dashboard/exams" component={ Exam } />
</Switch>
</div>
When I visit localhost:3000/admin/dashboard I get to see the Dashboard component. But when I navigate to localhost:3000/admin/dashboard/exams I am greeted with the 404 page.
Where am I going wrong?
App.js:
<Switch>
<Route path="/admin/dashboard" component={ AdminPanel } />
<Route path="/404" component={ NoMatch } />
<Route component={ NoMatch } />
</Switch>
AdminPanel.js
import {Redirect} from 'react-router-dom'
<Switch>
<Route exact path="/admin/dashboard" component={ Dashboard } />
<Route exact path="/admin/dashboard/exams" component={ Exam } />
<Route render={({location}) => <Redirect to={{
pathname: '/404',
state: { originalUrl: location.pathname}
}} />} />
</Switch>
later in the NoMatch component, you can access it under props.location.state.originUrl
I have my app and I want to add an admin routes. The problem is my header and footer are rendered on every route so when I'm trying to access admin panel they are rendered too. How can I separate 2 different routes for 2 different apps (not exactly but I hope u'll understand).
This is how my router looks like:
<Router>
<Container>
<Header/> // it is intended
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/news/:category/:id/:title' component={ SingleArticle } />
<Route path='/news' component={ Home } />
<Route path='/live' component={ Live } />
<Route path='/admin' component={ AdminPanel } /> //here I want all my admin routes which generates its own header and footer
<Route path='*' component={ NotFound } />
</Switch>
<Footer /> // it is intended
</Container>
</Router>
You can have different routes for admin and non-admin. You can do following:
if(admin) {
return (
<Router>
<Header>
// ... routes here
</Header>
</Router>
)
} else {
return (
<Router>
<AdminHeader />
// ... routes
</Router>
)
}
You can make use of a layout type component that takes a component as a prop, adds the necessary components to it and returns an new component like so:
const Layout = ({ children }) => {
return (
<section>
<Header/>
{children}
<Footer/>
</section>
)
}
Then any component you want to render with the header and footer you can declare as a child of the layout component:
<Router>
<Container>
<Switch>
<Route path='/admin' component={ AdminPanel } /> //here I want all my admin routes which generates its own header and footer
<Layout>
<Route exact path='/' component={ Home } />
<Route path='/news/:category/:id/:title' component={ SingleArticle } />
<Route path='/news' component={ Home } />
<Route path='/live' component={ Live } />
<Route path='*' component={ NotFound } />
</Layout>
</Switch>
</Container>
</Router>
You can use useLocation() Hook to find paths and separate routes.
eg:
import { useLocation } from 'react-router-dom'
if (useLocation().pathname.includes("/admin")) {
return (
<Switch>
<Route exact path="/admin" component={Admin} />
</Switch>
);
} else {
return (
<div className="App">
<Navbar />
<Switch>
// Routes goes
</Switch>
</div>
);