On a project I just started on reactjs, I should hide an element when the url changes. I searched and did not find something useful.
I would like to hide the Sidebar when the url is not Search.
Thanks to anyone who wants to give me a hand.
import React from 'react';
import { Routes, Route } from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.css';
import 'react-bootstrap';
import './App.css';
import NavBarTop from './components/layouts/header/NavBar_top';
import Sidebar from './components/layouts/Sidebar';
import Home from './components/pages/Home';
import Login from './components/pages/Login';
import Register from './components/pages/Register';
import Search from './components/pages/Search';
import E404 from './components/pages/E404';
function App() {
return (
<>
<div>
<NavBarTop />
<div className="container-fluid maincon">
<Sidebar />
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/search" element={<Search />} />
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
</>
);
}
export default App;
I would like to hide the Sidebar when the url is not Search.
Just render the Sidebar only with the Search component instead of unconditionally with everything.
<div>
<NavBarTop />
<div className="container-fluid maincon">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route
path="/search"
element={(
<>
<Sidebar />
<Search />
</>
)}
/>
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
If you wanted to render Sidebar with several routes, then create a layout component. Nested/wrapped Route components are rendered into the Outlet component.
import { Outlet } from 'react-router-dom';
const SidebarLayout = () => (
<>
<Sidebar />
<Outlet />
</>
);
...
<div>
<NavBarTop />
<div className="container-fluid maincon">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route element={SidebarLayout}>
<Route path="/search" element={<Search />} />
... other routes to render with sidebar ...
</Route>
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
there are multiple ways to do that.. this is only one...
export default function Wrapper() {
const urlWindow = window.location;
console.log(urlWindow.pathname.split("/")[1]);
const acceptedPaths = ["login", "register", "search", "test"];
return (
<>
<div>
navbar
<div className="container-fluid">
<div className="row">
{acceptedPaths.includes(urlWindow.pathname.split("/")[1]) ? (
<>
<Sidebar />
<MainContent />
</>
) : "Show 404 page"}
</div>
</div>
</div>
</>
);
}
const Sidebar = () => {
return <div className="col-md-2">I'm sidebar</div>;
};
const MainContent = () => {
return <div className="col-md-10">I'm main content</div>;
};
Firstly, you need import useLocation in react-router-dom
import { Routes, Route, useLocation } from "react-router-dom";
and call it in App function to get the current URL path which is used to check against /search for hiding/showing SideBar
function App() {
const location = useLocation();
const currentPath = location.pathname
return (
<>
<div>
<NavBarTop />
<div className="container-fluid maincon">
{currentPath === '/search' && <Sidebar />}
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/search" element={<Search />} />
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
</>
);
}
you can use hook named as useSearchParam
const [searchParams, setSearchParams] = useSearchParams();
to get query/url params as string.
Related
I have looked at the previous questions and googled for the answer and I think I almost know what the issue in here is, but don't know how to solve it.
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
{admin && (
<>
<Topbar />
<div className="container">
<Sidebar />
<Route path="/" element={<Home />} />
<Route path="/users" element={<UserList />} />
<Route path="/user/:userId" element={<User />} />
<Route path="/newUser" element={<NewUser />} />
<Route path="/products" element={<ProductList />} />
<Route path="/product/:productId" element={<Product />} />
<Route path="/newproduct" element={<NewProduct />} />
</div>
</>
)}
</Routes>
</Router>
Please tell me how to setup the topar and slidebar components here.
Requesting my fellow coders to look at this one and thanks in advance.
The error is clear, you only can use the <Route /> tag, and remove the <div className="container"> also.
Try this:
return (
<>
<Topbar />
<Sidebar />
<Router>
<Routes>
<Route path="/login" element={<Login />} />
{admin && (
<>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UserList />} />
<Route path="/user/:userId" element={<User />} />
<Route path="/newUser" element={<NewUser />} />
<Route path="/products" element={<ProductList />} />
<Route path="/product/:productId" element={<Product />} />
<Route path="/newproduct" element={<NewProduct />} />
</>
)}
</Routes>
</Router>
</>
)
Or you can import your TOPBAR and SIDEBAR components inside every other component.
to render a login page without a topbar and sidebar create a private router component and wrap it around all the routes you want to render a topbar and sidebar with
use react-outlet
here is what worked for me
app.js
import "./App.css";
import Sidebar from "./Components/Sidebar/Sidebar";
import TopBar from "./Components/TopBar/TopBar";
import Home from "./Pages/Home/Home";
import UserList from "./Pages/UserList/UserList";
import { BrowserRouter, Routes, Route } from "react-router-dom";
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 { useSelector } from "react-redux";
import Login from "./Pages/Login/Login";
import { Outlet } from "react-router-dom";
const SidebarLayout = () => (
<>
<TopBar />
<div className="container">
<Sidebar />
<Outlet />
</div>
</>
);
function App() {
// const admin = useSelector((state) => state.user.currentUser.isAdmin);
const admin = JSON.parse(
JSON.parse(localStorage.getItem("persist:root")).user
).currentUser.isAdmin;
return (
<BrowserRouter>
<Routes>
<Route element={<SidebarLayout />}>
<Route index element={<Home />} />
<Route exact path="/users" element={<UserList />} />
<Route exact path="/users/:id" element={<User />} />
<Route exact path="/newUser" element={<NewUser />} />
<Route exact path="/products" element={<ProductList />} />
<Route exact path="/products/:id" element={<Product />} />
<Route exact path="/newProduct" element={<NewProduct />} />
</Route>
<Route exact path="/login" element={<Login />} />
</Routes>
</BrowserRouter>
);
}
export default App;
import React from "react";
import { Router, Routes, Route } from "react-router-dom";
import Home from "./Home";
import UserList from "./UserList";
import NewUser from "./NewUser";
import ProductList from "./ProductList";
import Product from "./Product";
import NewProduct from "./NewProduct";
import Login from "./Login";
const AppRoute = () => {
return (
<>
{admin ? (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UserList />} />
<Route path="/user/:userId" element={<User />} />
<Route path="/newUser" element={<NewUser />} />
<Route path="/products" element={<ProductList />} />
<Route path="/product/:productId" element={<Product />} />
<Route path="/newproduct" element={<NewProduct />} />
</Routes>
</Router>
) : (
<Router>
<Routes>
<Route path="/" element={<Login />} />
</Routes>
</Router>
)}
</>
);
};
export default AppRoute;
const admin = JSON.parse(
JSON.parse(localStorage.getItem("persist:root")).user
).currentUser.isAdmin;
return (
<Router>
<>
<Topbar />
<div className="container">
<Sidebar />
<Routes>
<Route
path="/login"
element={admin ? <Navigate to="/" /> : <Login />}
/>
<Route exact path="/" element={<Home />}></Route>
<Route path="/users" element={<UserList />}></Route>
<Route path="/user/:userId" element={<User />}></Route>
<Route path="/newUser" element={<NewUser />}></Route>
<Route path="/products" element={<ProductList />}></Route>
<Route path="/product/:productId" element={<Product />}></Route>
<Route path="/newproduct" element={<NewProduct />}></Route>
</Routes>
</div>
</>
</Router>
); ```
the problem is the following. in the app.js is spelled out Routes and the home component. the home contains a navbar that navigates the site, only if you go to any page, it is drawn on top of the home. And if you switch to the home itself, it will be duplicated. Articles on the internet did not help, as did the addition of exact in route path.
function App() {
return (
<div className="messenger">
<Routes>
<Route path="/home/" element={<Home/>}/>
<Route path="/settings/" element={<Settings/>}/>
<Route path="/login/" element={<Login/>}/>
<Route path="/register/" element={<Register/>}/>
</Routes>
<Home/>
</div>
)
home
export default class Home extends Component {
render() {
return (
<div>
<NavBar/>
<ChatMenu/>
</div>
);
}
}
an example of how it is written in the navbar
export const NavBar = () => {
return (<div className="navbar-cm">
<div className="nav_element">
<Link to="/home">
<img src={homeIMG} className="nav_element"/>
</Link>
</div>
and a few more similar ones
</div>);
};
Issue
You are rendering the Home component again once outside the routes, this is why it's rendered with all routes including twice when on the "/home" path that renders Home.
function App() {
return (
<div className="messenger">
<Routes>
<Route path="/home/" element={<Home />} />
<Route path="/settings/" element={<Settings />} />
<Route path="/login/" element={<Login />} />
<Route path="/register/" element={<Register />} />
</Routes>
<Home /> // <-- always rendered below routed content
</div>
)
}
Solution
Remove the Home component that is out on its own outside the routes.
function App() {
return (
<div className="messenger">
<Routes>
<Route path="/home/" element={<Home />} /> // <-- now only Home component rendered
<Route path="/settings/" element={<Settings />} />
<Route path="/login/" element={<Login />} />
<Route path="/register/" element={<Register />} />
</Routes>
</div>
)
}
Remove <Home /> from the router:
function App() {
return (
<div className="messenger">
<Routes>
<Route path="/home/" element={<Home/>}/>
<Route path="/settings/" element={<Settings/>}/>
<Route path="/login/" element={<Login/>}/>
<Route path="/register/" element={<Register/>}/>
</Routes>
</div>
)
I am using use location to hide the navbar if the pathname name is /admin, /employee, /publisher. but I got an error saying that Error: useLocation() may be used only in the context of a <Router> component.
This is My App.js
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
const location = useLocation()
return (
<>
<UserState>
<Router>
{!["/admin", "/employee", "/publisher"].includes(location.pathname) && <Navbar/>} //For to hide the navbar if the pathname is /admin, /employee, /publisher
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route exact path="/" element={<Home />} />
<Route exact path="/service" element={<Service />} />
<Route exact path="/contact" element={<Contact />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/reset" element={<Reset />} />
<Route exact path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Route>
</Routes>
</Router>
</UserState>
</>
);
}
export default App;
The useLocation hook (and all other react-router-dom hooks) need a router above it in the ReactTree so that a routing context is available.
2 options:
Move the Router component up the tree and wrap the App component so it can use the useLocation hook.
import { BrowserRouter as Router } from 'react-router-dom';
...
<Router>
<App />
</Router>
...
import { Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
const location = useLocation();
return (
<UserState>
{!["/admin", "/employee", "/publisher"].includes(location.pathname) && <Navbar/>}
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" element={<Home />} />
<Route path="/service" element={<Service />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
<Route path="/reset" element={<Reset />} />
<Route path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Routes>
</UserState>
);
}
export default App;
Move the useLocation hook down the tree so that it's used within the Router component.
import { Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
return (
<UserState>
<Router>
<Navbar/>
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" element={<Home />} />
<Route path="/service" element={<Service />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
<Route path="/reset" element={<Reset />} />
<Route path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Routes>
</Router>
</UserState>
);
}
export default App;
...
const Navbar = () => {
const location = useLocation();
return !["/admin", "/employee", "/publisher"].includes(location.pathname)
? /* Return navbar JSX here */
: null;
};
useLocation() hook is used to extract the current location from the router.
For this purpose it's need the router context to pass the Location content
So if you want to use this hook, you need to use it in one of the nested components in <Router> Provider.
For your situation, you need to move the hook into the navbar component.
import { useLocation } from 'react-router-dom';
function Navbar() {
const location = useLocation()
if(["/admin", "/employee", "/publisher"].includes(location.pathname))
return <></>
return (
<>
I'm a navbar
</>
);
}
export default Navbar;
I am a beginner with react-router-dom, there are two different states in the code when I dont use Navigate from react-router-dom , it works properly , but when I use the Navigate function it renders a blank page.
I have confirmed that all the individual components work and render properly.
Please help me solve this issue .
Here is my code of App.js without Navigate
import React from 'react';
import { Container } from '#material-ui/core';
import { BrowserRouter , Route , Routes , Navigate } from 'react-router-dom'
import PostDetails from './components/PostDetails/PostDetails';
import Home from './components/Home/Home';
import Navbar from './components/Navbar/Navbar';
import Auth from './components/Auth/Auth';
const App = () => {
const user = JSON.parse(localStorage.getItem('profile'));
return (
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route exact path="/" element ={<Home/>} />
<Route path="/auth" element={<Auth/>} />
<Route path="/posts" exact element={<Home/>} />
<Route path="/posts/search" exact element={<Home/>} />
<Route path="/posts/:id" exact element={<PostDetails/>} />
<Route path="/auth" exact element={() => (!user ? <Auth /> : <Navigate to="/posts" />)} />
</Routes>
</Container>
</BrowserRouter>
)
};
export default App;
Here is my code of App.js with Navigate which does not works
import React from 'react';
import { Container } from '#material-ui/core';
import { BrowserRouter , Route , Routes , Navigate } from 'react-router-dom'
import PostDetails from './components/PostDetails/PostDetails';
import Home from './components/Home/Home';
import Navbar from './components/Navbar/Navbar';
import Auth from './components/Auth/Auth';
const App = () => {
const user = JSON.parse(localStorage.getItem('profile'));
return (
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route path="/" exact component={() => <Navigate replace to="/posts" />} />
<Route path="/posts" exact element={<Home/>} />
<Route path="/posts/search" exact element={<Home/>} />
<Route path="/posts/:id" exact element={<PostDetails/>} />
<Route path="/auth" exact element={() => (!user ? <Auth /> : <Navigate replace to="/posts" />)} />
</Routes>
</Container>
</BrowserRouter>
)
};
export default App;
In react-router-dom#6 the Route components's element prop takes only a ReactNode, a.k.a. JSX. You've one route taking a component prop which is invalid, and two routes passing a function.
Use the element prop and pass JSX only.
Note that there is also no longer any exact prop, in RRDv6 all routes are always exactly matched.
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route path="/" element={<Navigate replace to="/posts" />} />
<Route path="/posts" element={<Home />} />
<Route path="/posts/search" element={<Home />} />
<Route path="/posts/:id" element={<PostDetails />} />
<Route
path="/auth"
element={!user ? <Auth /> : <Navigate replace to="/posts" />}
/>
</Routes>
</Container>
</BrowserRouter>
If you are trying to protect these "/posts*" routes then it is common to create a layout route to handle redirecting to the login route or render the protected routes.
Example:
const AuthLayout = ({ authenticated }) =>
authenticated
? <Outlet />
: <Navigate to="/auth" replace />;
...
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route element={<AuthLayout authenticated={!!user} />}>
<Route path="/posts" element={<Home />} />
<Route path="/posts/search" element={<Home />} />
<Route path="/posts/:id" element={<PostDetails />} />
</Route>
<Route path="/" element={<Navigate replace to="/posts" />} />
<Route
path="/auth"
element={!user ? <Auth /> : <Navigate replace to="/posts" />}
/>
</Routes>
</Container>
</BrowserRouter>
use element props instead component
<Route path="/" exact component={() => <Navigate replace to="/posts" />} />
<Route path="/" exact element={() => <Navigate replace to="/posts" />
I want to put a div inside <Routes> and also Render a <Topbar /> and <Sidebar /> component inside <Routes> without <Route> tag for them.
My code is as follows:-
const App = () => {
return (
<Router>
<Routes>
<Route path="login" element={<Login />} />
<Topbar />
<div className="container">
<Sidebar />
<Route path="/" element={<Home />} />
<Route path="users" element={<UserList />} />
</div>
</Routes>
</Router>
);
};
I want to implement <Topbar /> and <Sidebar /> for all the routes.
But for an exception of login Page (Topbar and Sidebar should not be shown on the login page).
That's why I had put login Route at the top of Topbar and Sidebar.
The console is showing error as:
Uncaught Error: [Topbar] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
How to implement this functionality?
In react-router-dom v6 only Route and React.Fragment components are valid children for the Routes component.
Use layout components to render the Topbar and Sidebar components along with an Outlet for nested routes for the routes you want to render these components.
Example:
import { Routes, Route, Outlet } from 'react-router-dom';
const Layout = () => (
<>
<Topbar />
<div className="container">
<Sidebar />
<Outlet />
</div>
</>
);
const App = () => {
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="users" element={<UserList />} />
</Route>
</Routes>
</Router>
);
};
Change your routes like below,
you need to check whether user is logged in or not, if user logged in use Tobbar, Sidebar etc, otherwise just return login route
const App = () => {
const [isLogin, setIsLogin] = useState(false)
return (
<Router>
<Routes>
{ isLogin ? <Topbar />
<div className="container">
<Sidebar />
<Route path="/" element={<Home />} />
<Route path="users" element={<UserList />} />
</div> : <Route path="login" element={<Login />} />
</Routes>
</Router>
);
};