How to show default component always in react router - javascript

I want to show the header page always in every route.How to do this. I want props.history to be accessible inside that header component so that if i click any thing i can navigate to other page using props.history.push();
<BrowserRouter>
<div>
<Header/> // I want history in this component
<Route exact path="/" component={HomePage} />
<Route path="/page1" component={Page1} />
<Route path="/page2" component={Page2} />
</div>
</BrowserRouter>
);

Use Switch to render one route at a time. If you want history in Header component use withRouter from react-router. (history will be passed as a prop to the header component)
https://reacttraining.com/react-router/web/api/withRouter
/* header component */
import { withRouter } from 'react-router'
export default withRouter(Header)
/* router component */
<BrowserRouter>
<div>
<Header/> // I want history in this component
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/Picklistscreen" component={PickListArea} />
<Route path="/scanarea" component={ScanArea} />
</Switch>
</div>
</BrowserRouter>

You can create a Layout container which will render your header. If you set path="/" and without exact, it will render thru all routes.
<BrowserRouter>
<div>
<Route path="/" component={Layout} />
<Route exact path="/" component={HomePage} />
<Route exact path="/Picklistscreen" component={PickListArea} />
<Route exact path="/scanarea" component={ScanArea} />
</div>
</BrowserRouter>

Related

React router always display at the bottom the Error page

I'm having a problem regarding using of error page in my react app. The 404 page always shows at the bottom of every page that I render. I'm new to react. I hope someone can help me.
This is my App.js
import {BrowserRouter as Router,Switch,Route} from 'react-router-dom';
import Login from './components/auth/Login';
import Register from './components/auth/Register';
import ErrorPage from './components/ErrorPage';
import Order from './components/Order';
import Navbar from './components/partials/Navbar';
import Footer from './components/partials/Footer';
import Shop from './components/Shop';
import ItemDetails from './components/ItemDetails';
import Cart from './components/Cart';
import Customize from './components/Customize';
const App = () => {
return (
<>
<Router>
<Switch>
<Route exact path='/login'>
<Login />
</Route>
<Route exact path='/register'>
<Register />
</Route>
<div>
<Navbar />
<Route exact path='/'>
<Shop />
</Route>
<Route exact path='/order'>
<Order />
</Route>
<Route exact path='/item/details'>
<ItemDetails />
</Route>
<Route exact path='/cart'>
<Cart />
</Route>
<Route exact path='/customize'>
<Customize />
</Route>
<Route component={ErrorPage} />
</div>
</Switch>
</Router>
<Footer />
</>
);
}
export default App;
I searched about handling error page in react and I see that the order of routes is important but I don't get why I'm still getting the error page even it's in the bottom. Thank you guys.
That's because the switch component returns the first child at the root that meets the path condition. If the path condition doesn't exist it's evaluated as true. In your case you have 3 child Login, Register and the div which will always be evaluated to true. So just move all routes to the root of your switch:
<Router>
<Switch>
<Route exact path='/login'>
<Login />
</Route>
<Route exact path='/register'>
<Register />
</Route>
<div>
<Navbar />
<Switch>
<Route exact path='/'>
<Shop />
</Route>
<Route exact path='/order'>
<Order />
</Route>
<Route exact path='/item/details'>
<ItemDetails />
</Route>
<Route exact path='/cart'>
<Cart />
</Route>
<Route exact path='/customize'>
<Customize />
</Route>
<Route component={ErrorPage} />
</Switch>
</div>
</Switch>
</Router>

Route renders wrong component, ReactJS

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.

How do I nest routes with React router

I have multiple layouts that should include different screens. Each layout has its own header, footer, and other things similar pages should share. Here is the code I came up with:
<BrowserRouter>
<Route path={['/index', '/about']} component={BaseLayout}>
<Route path="/index" component={Index} />
<Route path="/about" component={About} />
</Route>
<Route path={['/sign-in', '/sign-up']} component={AuthLayout}>
<Route path="/sign-in" component={SignIn} />
<Route path="/sign-up" component={SignUp} />
</Route>
<Route path={['/stats'} component={DashboardLayout}>
<Route path="/stats" component={Stats} />
</Route>
</BrowserRouter>
The code above obviously won't work because:
Warning: You should not use <Route component> and in
the same route; <Route component> will be ignored
Answers to similar questions on SO suggest to use wrapper components directly:
<BrowserRouter>
<BaseLayout>
<Route path="/index" component={Index} />
<Route path="/about" component={About} />
</BaseLayout>
<AuthLayout>
<Route path="/sign-in" component={SignIn} />
<Route path="/sign-up" component={SignUp} />
</AuthLayout>
<DashboardLayout>
<Route path="/stats" component={Stats} />
</DashboardLayout>
</BrowserRouter>
Problem with this approach is that even that it renders a single screen, it also renders elements from the other layouts, i.e. if you're on the index page rendered inside the BaseLayout, you will see elements from the AuthLayout and DashboardLayout too. Which kinda makes sense because they are not wrapped in a Route.
Some people suggested to grab the content of all layouts and add them as siblings to the current Routes. However this is a mess to me. I do want to keep all layouts in separate files and only pass screens as children to them.
This is a rough draft of a potential layout structure:
<Header>
<Route>
<Route path={['/index', '/about']} component={HeaderComponent} />
<Route path={['/sign-in', '/sign-up']} component={AuthHeaderComponent} />
</Route>
</Header>
<Screens>
<Route>
<Route path="/index" component={BaseLayout(Index)} />
<Route path="/about" component={BaseLayout(About)} />
<Route path="/sign-in" component={AuthLayout(SignIn)} />
<Route path="/sign-up" component={AuthLayout(SignUp)} />
<Route path="/stats" component={DashboardLayout(Stats)} />
</Route>
</Screens>
<Footer>
<FooterComponent />
</Footer>
In this example the wrappers are HOCs so they can handle passing all props from the route down to the page component, but if you just wanted to do an inline wrapper you could use the render function:
<Route
path="/index"
render={routeProps => {
return (
<BaseLayout>
<Index {...routeProps}/>
</BaseLayout>
);
}}
/>
[edit] A sample Layout HOC (docs)
const withBaseLayout = WrappedComponent => {
// any business logic required for the layout
// layoutProps, style, etc...
return (
<BaseLayout {...layoutProps}>
<WrappedComponent {...this.props} /> // these are all the passed in props
// you can inject more props into Wrapped component as well
// i.e. redux's connect or react-router-dom's withRouter HOCs
</BaseLayout>
);
}
// in index.js
export default withBaseLayout(Index);
// in route
<Route path="/index" component={Index} /> // already wrapped
Or directly as Component
const BaseLayoutHOC = WrappedComponent => {
// any business logic required for the layout
// layoutProps, style, etc...
return (
<BaseLayout {...layoutProps}>
<WrappedComponent {...this.props} />
</BaseLayout>
);
}
// in route
<Route path="/index" component={BaseLayoutHOC(Index)} />

How to perform dynamic component rendering using react router v4?

I have an application with a Login page followed by a Dashboard page. The routes that I've defined in the index.js are like this:
<Router>
<div>
<Route exact path="/" component={Login}/>
<Route path="/dashboard" component={Dashboard} />
</div>
</Router>
Dashboard.js:
return (
<div>
<Header/>
<Footer/>
<Switch>
<Route path="/dashboard/content1" component={content1} />
<Route path="/dashboard/content2" component={content2} />
</Switch>
</div>
);
The Dashboard component is rendering 3 of its child components. Header, Footer and Content1. I want the Dashboard component to render Content1 by default (i.e. when the url is /dashboard) and also when the url is /dashboard/content1, and should render content2 when the url is /dashboard/content2. Header & Footer components should remain. Please suggest the configuration for the Dashboard component to achieve the same.
In React-router v4 you provide Routes within the component, so you can write your Routes as follows
<Router>
<div>
<Route exact path="/" component={Login}/>
<Route path="/dashboard" component={Dashboard} />
</div>
</Router>
and then in the Dashboard Component render method
render() {
return (
<div>
{/* other content */}
<Switch>
<Route exact path="/dashboard" component={content1} />
<Route path="/dashboard/content1" component={content1} />
<Route path="/dashboard/content2" component={content2} />
</Switch>
</div>
)
}
As a variant of an answer to your post before you have edited it, you can do it (nesting) like this:
<Router>
<Header/>
<Content1/>
<Footer/>
<Switch>
<Route exact path="/" component={Login}/>
<Route exact path="/dashboard" component={Dashboard} />
<Route exact path="/dashboard/content1" component={content1} />
<Route exact path="/dashboard/content2" component={content2} />
</Switch>
</Router>
React-Router's Switch component renders the first thing that matches,
so if you put a route without a path last, it will render that if no other routes match, essentially treating it as a default. Like so:
return (
<div>
<Header/>
<Footer/>
<Switch>
<Route path="/dashboard/content2" exact component={Content2} />
<Route component={Content1} />
</Switch>
</div>
);
I have found that rendering a component instead of a Route also works, although I dont know if it's officially supported.
return (
<div>
<Header/>
<Footer/>
<Switch>
<Route path="/dashboard/content2" exact component={Content2} />
<Content1 />
</Switch>
</div>
);

Default component in nested routes in React Router

In React Router I have a nested Route
<Route path='about' component={{main: About, header: Header}}>
<Route path='team' component={Team} />
</Route>
So now it shows Team when I go to /about/team.
But how do I set which Component to be seen when I visit /about?
I have tried
<Route path='about' component={{main: About, header: Header}}>
<IndexRoute component={AboutIndex} />
<Route path='team' component={Team} />
</Route>
and
<Route path='about' component={{main: About, header: Header}}>
<Route path='/' component={AboutIndex} />
<Route path='team' component={Team} />
</Route>
but it doesn't work.
My About component looks like this
class About extends React.Component {
render () {
return (
<div>
<div className='row'>
<div className='col-md-9'>
{this.props.children}
</div>
<div className='col-md-3'>
<ul className='nav nav-pills nav-stacked'>
<li className='nav-item'><IndexLink className='nav-link' to='/about' activeClassName='active'>About</IndexLink></li>
<li className='nav-item'><Link className='nav-link' to='/about/team'>Team</Link></li>
</ul>
</div>
</div>
</div>
);
}
}
REACT ROUTER 4 UPDATE
The default route is the one without a path.
import BrowserRouter from 'react-router-dom/BrowserRouter';
import Switch from 'react-router-dom/Switch';
import Route from 'react-router-dom/Route';
<BrowserRouter>
<Switch>
<Route exact path='/about' component={AboutIndex} />
<Route component={AboutIndex} /> // <--- don't add a path for a default route
</Switch>
</BrowserRouter>
If you don't need this object {main: About, header: Header} in your component, then just put AboutIndex in the component attribute. That should work
<Router history={browserHistory}>
<Route path='about' component={AboutIndex}>
<IndexRoute component={AboutIndex} />
<Route path='team' component={Team} />
</Route>
</Router>
If you still need main and header components, just add them in as either parent, child, or sibling components depending on your needs
React Router v6
The route has an attribute index which is used to define the index route as per the docs.
<Route index element={<DefaultPage />} />
Another way to do I found is to use the Navigate component of the react-router-dom package with the index attribute. After the a user navigates to the support route, it will default to the about page in the following example.
<Route path="support/*" element={<Support />}>
<Route index element={<Navigate to="about" replace />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact/>} />
</Route>

Categories

Resources