Show a navigation component on all routes except the root - reactjs

I need to show a main navigation on all routes except the root route. If I was going to show on all routes I would do it like this:
class App extends Component {
render() {
return (
<Container className="App" maxWidth="lg">
<Grid className="app-container">
<MainNav />
<Switch>
<Route exact path="/" component={Home} />
<Route
exact
path="/some-other-route"
component={SomeOtherComponent}
/>
...
</Switch>
</Grid>
</Container>
);
}
}
I could make a wrapper component for all the other routes and put it there, but any solution I can think of to accomplish this just seems wrong and there's probably a better way. Is there a better way?

Maybe you can use this code.
The below code is inspired by nextjs page routing.
You just add your routes on ~/pages/ and it imports them dynamically.
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
function DynamicRoutes() {
return (
<BrowserRouter>
<Switch>
<Route
path="/"
render={({ history, location, match })=>{
const Page = React.lazy(()=>{
return import('./pages'+location.pathname).catch((e) => {
if (/not find module/.test(e.message)) {
return import("./pages/NotFound");
}
if (/Loading chunk \d+ failed/.test(e.message)) {
window.location.reload();
return;
}
throw e;
})
});
return (
<React.Suspense fallback ={<div>Loading...</div>}>
<Page />
</React.Suspense>
)
}}
/>
</Switch>
</BrowserRouter>
)
}
export default DynamicRoutes;

Related

why Route is not working with my react app?

I am trying to develop react application. The problem is when I use the Route and Switch, it is not working. Actually, nothing is happening. Could anyone please give me a clue about the possible problem here?
Here is my code:
import React, { Component } from 'react';
import Home from './HomeComponent';
import Menu from './MenuComponent';
import { DISHES } from '../shared/dishes';
import DishDetailComponent from './DishdetailComponent';
import Header from './HeaderComponent';
import Footer from './FooterComponent';
import { Switch, Route, Redirect, BrowserRouter as Router } from 'react-router-dom';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES
};
}
render() {
const HomePage = () => {
return(
<Home />
);
}
return (
<div>
<Header />
<Router>
<Switch>
<Route path="/home" Component={HomePage} />
<Route path="/menu" Component={() => <Menu dishes={this.state.dishes} />} />
<Redirect to="home" />
</ Switch>
</Router>
<Footer />
</div>
);
}
}
The obvious mistake is that you have capitalized the "C" in the component prop, so you should call it like component={HomePage}
Here are some other things you could improve upon though:
If you are gonna use an inline function, it is preferable to use the render prop, and if you are gonna use a component directly, preferable to just use Component prop. Moreover:
const HomePage = () => {
return(
<Home />
);
}
is unnecessary as you can just use the Home component directly.
Try this for your render() function:
render() {
return (
<div>
<Header />
<Router>
<Switch>
<Route path="/home" component={Home} />
<Route path="/menu" render={() => <Menu dishes={this.state.dishes} />} />
<Redirect to="home" />
</ Switch>
</Router>
<Footer />
</div>
);
}

React router show only route without components defined in my browser

Hello in my directions file I set my struct
header
navbar
and my switch
foote
const AppRouter = () => (
<BrowserRouter>
<Route path="/login" component={AuthPage} exact={true} />
<Route path="/dashboard/addProduct" component={AddProduct} exact={true} />
<div>
<Header/>
<Navigation/>
<Container maxWidth="lg" >
<Switch>
<Route path="/" component={LandingPage} exact={true} />
<Route path="/xd" component={AuthPage} exact={true} />
<Route component={NotFoundPage} />
</Switch>
</Container>
</div>
</BrowserRouter>
);
But I have two routes where I didn't want to show my header
footer
and nav bar
which are the login and addproduct routes
how could i do that?
This is a little bit hacky (just to match your current approach) since I'm assuming you just want to hide those components in only those 2 routes, You can use withRouter in your Header and Navigation components, withRouter will provide to you the location prop and you can have a condition like this:
import React from "react";
import { withRouter } from "react-router-dom";
const Navigation = props => {
const { location } = props;
const { pathname } = location;
if (pathname !== "/login" || pathname !== "/dashboard/addProduct" ) {
return (
// Component logic goes here
);
}
// if we're on those routes we should return null to not render anything
return null;
};
export default withRouter(Navigation);
If you want a more robust long term approach this answer could help:
How to hide navbar in login page in react router

Use layout for certain routes in React

I need to maintain a section of my app available for all pages (most of the pages actually)
to do that I wrapped the routes in a Layout
<Router>
<Route path="/login" exact strict component={Login}/>
<Layout>
<Route path="/list" exact strict component={List}/>
<Route path="/settings" exact strict component={Settings}/>
</Layout>
</Router>
the Layout component looks like this
class Layout extends Component {
render() {
return (
<React.Fragment>
<div>this box should be visible in all pages using layout</div>
<div>{this.props.children}</div>
</React.Fragment>
)
}
}
this work perfectly fine. the only poblem is when I go to /login
is rendering the Login component and also the Layout component.
I shouldn´t render the Layout if is not for one of the ¨protected¨ routes.
is there a way to achieve that without moving the layout inside of the List of Settings component?
the reason for this is because the box that´s fixed in all pages makes one API request and there´s no need to do that same API call for /list and /settings. I do it only once.
hope this makes sense to you. thank you!
update:
"react-router-dom": "^5.0.1"
I've done a fair bit of research on the subject and came up with this. I have it set up in my routes:
import React from 'react'
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'
// import PublicRoute, PrivateRoute, Login, Private
<Router>
<Switch>
<PublicRoute exact path='/login' component={Login} />
<PrivateRoute path='/private' component={Private} />
</Switch>
<Router>
Then in my privateRoute.js:
import React from 'react'
import { Redirect, Route } from 'react-router-dom'
// import useAuth and PrivateLayout
export default ({ componet: Component, ...rest }) => {
const { token } = useAuth() // wrapper I wrote to handle auth
if (!token) return <Redirect to='/login' />
return (
<Route {...rest} render={props => (
<PrivateLayout><Component {...props} /></PrivateLayout>
)} />
)
}
And my publicRoute.js is similar but without authentication. My layouts are a simple wrapper, all you need to do is include children:
export default ({ children }) => {
return (
<>
<Topbar />
<Sidebar />
{children}
</>
)
Note: For those who don't know <> is the shorthand for <React.Fragment>.

Navigate to new URL from within MemoryRouter structure

When a user completes a booking process and navigate to the confirmed details view. I need the URL to change. This is proving to be difficult to work around as the routing in done through MemoryRouter which can neither read, nor write to the URL. I need to break one of the views out and have the browser navigate to this new view.
I have tried breaking out from one router and creating a second that would return based on the original URL, then tried the very hacky window.location and direct the url to the new router.
import React from 'react';
import { MemoryRouter, Route, Switch } from 'react-router-dom';
import {
Page,
StartScreen,
StoreSearch,
ServiceSelector,
StoreSelector,
OptionSelector,
AppointmentForm,
AppointmentDetails,
ConfirmationScreen,
ErrorScreen,
} from 'components';
import { WithPageTitle, ScrollToTop } from 'containers';
import { services } from 'utilities';
const NewAppRouter = () => {
return (
<MemoryRouter>
<ScrollToTop>
<Switch>
<Route exact path="/" component={StartScreen} />
<WithPageTitle>
{pageTitle => (
<Page pageTitle={pageTitle}>
<Route path="/zip" component={StoreSearch} />
<Route path="/services" component={() => ServiceSelector({
services: services.services,
withBackButton: true,
backTo: "/zip"
})} />
<Route path="/stores" component={StoreSelector} />
<Route path="/options" component={OptionSelector} />
<Route path="/form" component={AppointmentForm} />
<Route path="/details" component={AppointmentDetails} />
{/* <Route path="/confirmation" component={ConfirmationScreen} /> */}
<Route path="/error" component={ErrorScreen} />
</Page>
)}
</WithPageTitle>
</Switch>
</ScrollToTop>
</MemoryRouter>
)
}
const AppRouter = () => {
if(window.location.href="http://localhost:9998"){
return (
<NewAppRouter />
)
} else if (window.location.href="http://localhost:9998/confirmation") {
return (
<ConfirmRouter />
)
} else {
return console.error('Route Not Found')
}
}
export default AppRouter;

How to call a method from a component using Route in React Router v4?

I have some nested routes written in react router v4 and in the Navigation component I have an input box.
On submit I need to call a method on a different route (on Landing component) and pass the value. I can't find any example to call a method in Route.
Any other way/ workaround to use a navigation with data and different routes is welcome.
My routes:
return (
<div>
<Navigation callSearch = {this.callSearch.bind(this)} />
<Switch>
<Route path="/u/:slug" component={AuthorPage}/>
<Route path="/:location/:slug" component={PhotoDetails}/>
<Route path="/" component={Landing} />
</Switch>
</div>
)
In Navigation i call callSearch() :
searchPhotos(e) {
e.preventDefault();
if(this.state.searchTerm) {
this.props.callSearch(this.state.searchTerm);
}
}
I have fixed this issue in my application using withRouter from react-router module.
import { Route } from "react-router-dom";
import { withRouter } from "react-router";
class SideBar extends Component {
callSearch = (searchKeyword) => {
if(searchKeyword) this.props.history.push(`/u/${searchKeyword}`);
};
render() {
return (
<div>
<Navigation callSearch = {this.callSearch} />
<Switch>
<Route path="/u/:slug" component={AuthorPage}/>
<Route path="/:location/:slug" component={PhotoDetails}/>
<Route path="/" component={Landing} />
</Switch>
</div>
)
}
export default withRouter(SideBar);
Hope this will help anyone else !!!

Resources