I am implementing the global navigation sidebar (left collapsible) with react but I want to exclude or hide my sidebar from some routes or components.
and when I importing it to a particular component I am loosing my component responsiveness.
import React from "react";
//more imports are here
const App = () => (
<ThemeProvider theme={theme}>
<div>
<AppToolbar />
<div className="myclass">
<SideBar>
<Route path="/" exact component={Home} />
<Route path="/setting" component={Setting} />
<Route path="/help" component={Help} />
<Route path="/about" component={About} />
</SideBar>
</div>
</div>
</ThemeProvider>
);
export default App;
Looking for the solution to hide the sidebar from Route path="/" exact component={Home} /> route.
or is there any other way to achieve the same functionality.
Looks like the routes need to be taken out from the SideBar JSX first so that routes won't be wrapped inside SideBar indefinitely.
Pass a function props to the route components which can change the state of parent component's sidebar. Then at the route where you want to hide sidebar, call that function which will take the SideBar JSX out from the DOM.
Example:
import React from "react";
//more imports are here
const App = () => {
const [showSidebar,setShowSidebar] = React.useState();
const handleToggleSideBar = () => {
//togglesidebar with useState
setShowSidebar(!showSidebar);
}
return (
<ThemeProvider theme={theme}>
<div>
<AppToolbar />
<div className="myclass">
{showSidebar && <SideBar />}
<Route path="/" exact render={(props) => <Home toggleSideBar={handleToggleSideBar } {...props} />} />
<Route path="/setting" render={//do the same thing like Home} />
</div>
</div>
</ThemeProvider>
)};
export default App;
Home.jsx
export const Home = ({toggleSideBar}) => {
useEffect(() => {
toggleSideBar();
},[]);
}
Related
I created a page using react-router-dom. On that I set a navbar and on that navbar I put two links (FormControl, Accordion). When the user will click that link the main body will change, nav bar should not change, it should remain constant on the page.
I tried to fix the issue and I am expecting that when a user clicks the links the navbar will not change.
import Accordion from "./component/Accordion";
import FormControl from "./component/FormControl";
import NavBar from "./component/NavBar";
import NoPage from "./component/NoPage";
import { Routes, Route } from 'react-router-dom';
function App() {
return (
<>
<Routes>
<Route path="/" element={<NavBar />} />
<Route path="/Accordion" element={<Accordion />} />
<Route path="/FormControl" element={<FormControl />} />
<Route path="/*" element={<NoPage />} />
</Routes>
</>
);
}
export default App;
app.js
index.js
main nav bar
when clicking on form control the nav bar get hidden
If you want the NavBar component to renders always, or at least consistently with a group of routes you should render it alone on its own route. With NavBar rendered on "/" when the user navigates to any other route the "/" will no longer be the matched route and the NavBar component will be unmounted.
Examples
Unconditionally rendered on its own.
import { Routes, Route } from 'react-router-dom';
function App() {
return (
<>
<NavBar />
<Routes>
<Route path="/" element={/* Need a home page component? */} />
<Route path="/accordion" element={<Accordion />} />
<Route path="/formcontrol" element={<FormControl />} />
<Route path="*" element={<NoPage />} />
</Routes>
</>
);
}
As part of a layout route that renders an Outlet component for nested routes.
import { Routes, Route, Outlet } from 'react-router-dom';
const AppLayout = () => (
<>
<NavBar />
<Outlet />
</>
);
function App() {
return (
<Routes>
<Route path="/" element={<AppLayout />}>
<Route index element={/* Need a home page component? */} />
<Route path="accordion" element={<Accordion />} />
<Route path="formcontrol" element={<FormControl />} />
<Route path="*" element={<NoPage />} />
</Route>
</Routes>
);
}
I have nested routes, the third level routes are failing.
This is my routing structure
yeah.... but the problem is,
App.js Routes to
-Home
-About
-Dashboard
Then Dashboard has children component to
-Profile (/dashboard/user)
-Account (/dashboard/account)
-Wallet (/dashboard/wallet)
-Settings (/dashboard/settings)
Then Settings has other children components
-Edit Profile (/dashboard/settings/editprofile)
-Edit Password and Pin (/dashboard/settings/editpassword)
-Edit Account Number (/dashboard/settings/editnumber)
The top two level routes are working, but the last one fails when i refresh the page, although it renders when i go back to the homepage and click on the links till i get to the last component, but once i refresh my browser it breaks, also it doesn't work when i type it manually.
Here is my App.js Route setup
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
const App = () => {
return (
<div className="App">
{/* setting up the routes */}
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/dashboard" component={dashboard} />
<Route path="/login" exact component={Login} />
<Route path="/register" exact component={SignUp} />
<Route path="/about" exact component={AboutServices} />
</Switch>
</Router>
</div>
);
};
My DashBoard.js
import { Route, useRouteMatch, NavLink, Switch } from "react-router-dom";
const App = () => {
let { path, url } = useRouteMatch();
return (
<div className="App">
<nav> Navavigation bar <nav>
{/* setting up the routes */}
<div className="MainBody">
<Switch>
<Route path={`${path}/wallet`} exact component={Wallet} />
<Route path={`${path}/profile`} component={Profile} />
<Route path={`${path}/account`} component={Account} />
<Route path={`${path}/settings`} exact component={Settings} />
</Switch>
</div>
</div>
);
};
Settings Page
import {
Switch,
Route,
useRouteMatch,
NavLink,
BrowserRouter,
} from "react-router-dom";
const Settings = (props) => {
let { path, url } = useRouteMatch();
return (
<div className="Settings">
<BrowserRouter>
<nav> Navavigation bar <nav>
<div className="SettingsWrapper">
<Switch>
<Route path={`${path}/editprofile`} component={EditProfile} />
<Route
path={`${path}/changepassword`}
component={ChangePassword}
/>
<Route path={`${path}/changepin`} component={ChangePin} />
<Route
path={`${path}/accountsettings`}
component={BankSettings}
/>
</Switch>
</div>
</div>
</BrowserRouter>
</div>
);
};
export default Settings;
I am 99% sure your issue is because you are using more than 1 router. Remove the BrowserRouter around your Settings UI. I am guessing when the nested routes aren't navigated to via links from the outer router that the match prop isn't initialized as you expect it to be.
const Settings = (props) => {
let { path, url } = useRouteMatch();
return (
<div className="Settings">
<nav>Navigation bar</nav>
<div className="SettingsWrapper">
<Switch>
<Route path={`${path}/editprofile`} component={EditProfile} />
<Route
path={`${path}/changepassword`}
component={ChangePassword}
/>
<Route path={`${path}/changepin`} component={ChangePin} />
<Route
path={`${path}/accountsettings`}
component={BankSettings}
/>
</Switch>
</div>
</div>
);
};
Edit
Ok, when removing the nested router and creating my own codesandbox I found a small, subtle but important "quirk" of nesting routes. Any nested route that is rendering further routes can not specify the exact prop on the route.
const App = () => {
let { path, url } = useRouteMatch();
return (
<div className="App">
<nav>Navigation bar</nav>
{/* setting up the routes */}
<div className="MainBody">
<Switch>
...
<Route
path={`${path}/settings`}
exact // <-- exact match precludes sub-routes!!
component={Settings}
/>
</Switch>
</div>
</div>
);
};
So if for example the path was "/dashboard/settings/editprofile" the path no longer exactly matches the route path and the route is not rendered.
Solution
Simply omit the exact prop for nested routes rendering sub-routes. Remember that route paths are to be considered "prefixes", so without the exact prop specified that path "/dashboard/settings/editprofile" can be matched by "/dashboard/settings".
const Dashboard = () => {
let { path, url } = useRouteMatch();
return (
<div className="App">
<nav>Dashboard Navigation bar </nav>
<NavLink to={`${url}/settings`}>Settings</NavLink>
{/* setting up the routes */}
<div className="MainBody">
<Switch>
...
<Route path={`${path}/settings`} component={Settings} /> // <-- no exact match
</Switch>
</div>
</div>
);
};
I am working on a web application and my application works for the most part except I cannot see the /tasks section. I do not understand because it is the same as the rest of my elements.
import React, {
Component,
Fragment
} from 'react';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
import AppProvider, {
Consumer
} from './AppProvider';
import Login from './Login';
import Signup from './Signup';
import Navbar from './Navbar';
import FlashMessage from './FlashMessage';
class App extends Component {
render() {
return (
<AppProvider>
<Router>
<Fragment>
<Navbar />
<FlashMessage />
<Route exact path="/" component={() =>
<h1 className="content">Welcome, Home!</h1>} />
<Route exact path="/login" component={() => <Login />} />
<Route exact path="/signup" component={() => <Signup />} />
<Router exact path="/tasks" component={() =>
<h1 className="content">Content Should Go Here</h1>} />
<Route exact path="/signedOut" component={() =>
<h1 className="content">You're now signed out.</h1>} />
<Route exact path="/accountCreated" component={() =>
<h1 className="content">Account created. <Link
to="/login">
Proceed to Dashboard</Link></h1>} />
</Fragment>
</Router>
</AppProvider>
);
}
}
export default App;
The content div routed at /tasks won't display anything. There are no errors, I have checked in the console. All I want is it to display the content on /tasks.
I think the problem is you are using the BrowserRouter in your "./tasks" instead of use route.
The issue is because you have a trailing Slash on your link.
I want to hide the navbar in a login page.
I did it actually, but I can't see the navbar on other pages.
This code is part of My App.jsx file.
I make history in App's state. And I hide navbar, when this pathname is '/' or '/login'.
It works!
But then I typed the ID and password, and clicked the login button, got 'success' result, and navigated to '/main'.
Now I can't see navbar in main component too.
How can I do this?
Sorry about my short english. If you can't understand my question, you can comment.
constructor(props) {
super(props);
this.state = {
isAlertOpen: false,
history: createBrowserHistory(),
};
this.toggleAlert = this.toggleAlert.bind(this);
}
<BrowserRouter>
<div className="App">
{this.state.history.location.pathname === '/' || this.state.history.location.pathname === '/login' ? null
: <Header toggleAlert={this.toggleAlert} />}
<div className="container">
{this.state.history.location.pathname === '/' || this.state.history.location.pathname === '/login' ? null
: <Navbar />}
<Route exact path="/" render={() => <Redirect to="/login" />} />
<Route path="/login" component={Login} />
<Route path="/main" component={Main} />
<Route path="/user" component={User} />
<Route path="/hw-setting" component={Setting} />
<Route path="/hw-detail/:id" component={HwDetail} />
<Route path="/gas-detail/:id" component={GasDetail} />
{this.state.isAlertOpen ? <Alert /> : null}
</div>
</div>
</BrowserRouter>
login(event) {
event.preventDefault();
userService.login(this.state.id, this.state.password).subscribe(res => {
if (res.result === 'success') {
global.token = res.token;
this.props.history.push('/main');
} else {
alert(`[ERROR CODE : ${res.statusCode}] ${res.msg}`);
}
});
You could structure your Routes differently so that the Login component doesn't have the Header Like
<BrowserRouter>
<Switch>
<div className="App">
<Route exact path="/(login)" component={LoginContainer}/>
<Route component={DefaultContainer}/>
</div>
</Switch>
</BrowserRouter>
const LoginContainer = () => (
<div className="container">
<Route exact path="/" render={() => <Redirect to="/login" />} />
<Route path="/login" component={Login} />
</div>
)
const DefaultContainer = () => (
<div>
<Header toggleAlert={this.toggleAlert} />
<div className="container">
<Navbar />
<Route path="/main" component={Main} />
<Route path="/user" component={User} />
<Route path="/hw-setting" component={Setting} />
<Route path="/hw-detail/:id" component={HwDetail} />
<Route path="/gas-detail/:id" component={GasDetail} />
{this.state.isAlertOpen ? <Alert /> : null}
</div>
</div>
)
As of the latest release of React Router v6, it is no longer possible to pass a <div> component inside the Routes (v6) aka Switch(v5 or lower) to render a Navbar. You will need to do something like this:
Create two Layout components. One simply renders a Nav and the other one does not. Suppose we name them
<WithNav />
<WithoutNav />
You will need to import <Outlet /> from the React router and render inside the Layout components for the routes to be matched.
Then in your App or where ever you have your Router you will render like below ....
// WithNav.js (Stand-alone Functional Component)
import React from 'react';
import NavBar from 'your navbar location';
import { Outlet } from 'react-router';
export default () => {
return (
<>
<NavBar />
<Outlet />
</>
);
};
// WithoutNav.js (Stand-alone Functional Component)
import React from 'react';
import { Outlet } from 'react-router';
export default () => <Outlet />
// your router (Assuming this resides in your App.js)
<Routes>
<Route element={<WithoutNav />}>
<Route path="/login" element={<LoginPage />} />
</Route>
<Route element={<WithNav />}>
<Route path="/=example" element={<Example />} />
</Route>
</Routes>
LoginPage will not have a nav however, Example page will
Simplest way is use div tag and put components in which you want navbar and put login route component outside div tag:
<div className="App">
<Router>
<Switch>
<Route exact path="/" component={Login} />
<div>
<NavBar />
<Route exact path="/addproduct" component={Addproduct}></Route>
<Route exact path="/products" component={Products}></Route>
</div>
</Switch>
</Router>
</div>
Put the Route with path="/" below every other routes :
<Switch>
<Route path="/login" component={Login} />
<Route path="/" component={Home} />
</Switch>
It will work.
I'm was trying to solve this problem, what i did was add component helmet, to install it use : yarn add react-helmet --save.
import {Helmet} from 'react-helmet';
<Helmet>
<script src="https://kit.fontawesome.com/.....js" crossorigin="anonymous"></script>
</Helmet>
The accepted answer has problem if you need to add other default route within the switch if no other route matches, e.g., 404 page, not found page.
I ended up using simple css to hide navigation bar inside my login page.
class LoginPage extends React.Component<>{
...
// Hide navigation bar in login page. Do it inside ComponentDidMount as we need to wait for navbar to render before hiding it.
componentDidMount(){
document.getElementById('navigation-bar')!.style.display = "none";
}
componentWillUnmount(){
document.getElementById('navigation-bar')!.style.display = "flex";
}
render(){
return(
// your login/signup component here
...
)
}
}
I just started learning React, I'm trying to make a SPA blog, which has a global positioned fixed header.
import React from 'react';
import { render } from 'react-dom';
// import other components here
render((
<Router history={browserHistory}>
<Route path="/" component={Home} />
<Route path="/About" component={About} />
<Route path="/Contact" component={Contact} />
<Route path="*" component={Error} />
</Router>
), document.getElementById('app'));
So, each routes has the same header and from my angular background, I would use header outside ui-view.
Its a good practice to import the header component in each individual page component, or can I add the header component on my <Router><myHeader/><otherRoutes/></Router>?
Update:
I was thinking to use something like this:
Routes component, where I define my routes:
class Routes extends React.Component {
render() {
return (
<Router history={browserHistory}>
<IndexRoute component={Home} />
<Route path="/studio" component={Studio} />
<Route path="/work" component={Work} />
<Route path="*" component={Home} />
</Router>
)
}
}
And then on main Index.js file I would like to render something like:
import Routes from './components/Routes';
render((
<div>
<div className="header">header</div>
<Routes />
</div>
), document.getElementById('app'));
Can someone explain me? Thanks!
From my experience it can be good to define a layout component for your page, something like...
Layout Component
render() {
return(
<div>
<Header />
{ this.props.children }
/* anything else you want to appear on every page that uses this layout */
<Footer />
</div>
);
}
You then import layout into each of your page components...
Contact Page Component
render() {
return (
<Layout>
<ContactComponent />
/* put all you want on this page within the layout component */
</Layout>
);
}
And you can leave your routing the same, your route will render the contact page and in turn will render your header.
This way you get control of repetitive stuff that will be on multiple pages, if you need one or two slightly different pages you can just create another layout and use that.
I find this way useful:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from "./components/Header";
import Home from "./components/Home";
import Dashboard from "./components/Dashboard";
import Footer from "./components/Footer";
class App extends Component {
constructor() {
super();
this.state = {
stuff: stuff;
};
}
render() {
let { stuff } = this.state;
return (
<Router> //wrapper for your router, given alias from BrowserRouter
<div className="App">
<Header /> //this component will always be visible because it is outside of a specific Route
<Route exact path="/" component={Home}/> //at the root path, show this component
<Route path="/dashboard" component={()=><Dashboard stuff={stuff} />}/> //at the path '/dashboard', show this other component
<Footer /> //this is also permanently mounted
</div>
</Router>
);
}
}
export default App;
credit goes to: David Kerr
The question is already answered but I'm here to show another approach and say why I prefer that.
I also think that it's a good thing to have a Layout component
function Layout (props) {
return (
<div>
<Header/>
<div className="content">
{props.children}
</div>
</div>
);
}
But instead of render it into each route component you can render it just once as a parent for your routes.
return (
<Router>
<Layout>
<Switch>
<Route path="/about">
<About/>
</Route>
<Route path="/contact">
<Contact/>
</Route>
<Route path="/">
<Home/>
</Route>
</Switch>
</Layout>
</Router>
);
This is good because in most cases you will not waste time with the layout and if you have different layouts you only need to work inside the Layout component.
For forcefully refresh Header inside routing. use forceRefresh={true}
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}
I've another solution that is make the routing like this
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}
and in the header file edit as this
import React, {useLocation} from "react";
const header = () => {
const location = useLocation();
return(
<div className={location.pathname === 'login' ? 'd-none': 'd-block'}>
abc
</div>
)
}
export default header;
this will hide the header panel in login page.