Send prop with react route - javascript

I try to send a data called favProduct to Favourites component. When I send the data, I get undefined. How can I send a data when I use react route?
const [favProduct, setFavProduct] = useState([1,2,3,4,5]);
return (
<Router>
<div className="App">
<Header />
<Switch>
<Route path="/" exact component={Home}/>
<Route path="/men" component={Men} />
<Route path="/women" component={Women} />
<Route path="/kids" component={Kids} />
<Route path="/productBuy" component={ProductBuy} />
<Route path="/favourites" component={Favourites} />
<Route path="/cart" component={Cart} />
<Route path="/checkout" component={Checkout} />
<Route path="/addproduct" component={AddProduct} />
</Switch>
<Footer />
</div>
</Router>
);
}

If you want, or need, to send additional props to routed components, use the Route's render prop to inject the props and forward the route props.
Example:
<Route
path="/favourites"
render={props => <Favourites {...props} favProduct={favProduct} />}
/>
Access all the route props as done previously, i.e. props.location, props.history, etc... and access the new prop that was passed, i.e. props.favProduct.

If using react-router v6+, in your route, try this:
<Route path="/favourites" element={<Favourites favProduct={favProduct} />} />

Related

Why are my React components rendering in all routes?

This is the my App() function in App.js, the comps :"Sidebar, Feed and Widgets" keeps rendering in route ="/" and also ="/login" as well, in addition to that "Login" comp didn't even render in route ="/login".
<Router>
<div className="app">
<Switch>
<Route path="/">
<Sidebar />
<Feed />
<Widgets />
</Route>
<Route path="/login">
<Login />
</Route>
</Switch>
</div>
</Router>
If you are using the latest version of react-router-dom, you must change the Switch to Routes
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { Sidebar, Feed, Widgets } from '...'
const Home = () => {
return (
<Sidebar />
<Feed />
<Widgets />
)
}
const App = () => {
return (
<Router>
<div className="app">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
</Routes>
</div>
</Router>
)
}
You need to add exact with "/'" route.
In your case when you are not adding exact, React router will match '/login' path with the first path '/' and will render accordingly without checking next routes. By adding exact, first '/' will not match and it will match with second route '/login'.
<Router>
<div className="app">
<Switch>
<Route path="/" exact>
<Sidebar />
<Feed />
<Widgets />
</Route>
<Route path="/login">
<Login />
</Route>
</Switch>
</div>
</Router>
For more information, you can also refer this similar question: React : difference between <Route exact path="/" /> and <Route path="/" />
The Switch component exclusively matches and renders routes, so only 1 route can ever be matched. You've an issue with the order of your routes though, so only the "/" path matches since it's earlier and is rendered. The route for "/login" can never be reached, as-is.
In other words, this means is that when the path is "/login" that "/" still matches it and is the route rendered. In react-router-dom v5 think of the path props as a "path prefix".
In the Switch component, path order and specificity matter! You should order the paths from more specific to less specific. This allows more specific paths like "/login" to be matched before trying the less specific paths.
<Router>
<div className="app">
<Switch>
<Route path="/login">
<Login />
</Route>
<Route path="/">
<Sidebar />
<Feed />
<Widgets />
</Route>
</Switch>
</div>
</Router>

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 show default component always in react router

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>

React router redirect outside of route component

I use React Router in my React application.
In Header component that isn't inside Router component i want to redirect user after register a form, but because Header component is outside of Router component i can't use this.props.history.push('/');.
How can i redirect user in Header component?
This is my App component:
<div>
<Header order={this.order}/>
<Router data={this.state.data}>
<div>
<Menu data={this.state.data}/>
<Route exact path="/" component={Home} />
<Route exact path="/post" component={PostList} />
<Route path="/showpost/:slug" component={ShowPost} />
<Route path="/page/:slug" component={ShowPage} />
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Route path="/forgotpassword" component={Forgot} />
<Route path="/password/reset/:token" component={Reset} />
<Route path="/logout" component={Logout} />
<Route path="/user" component={User} />
<Route path="/saveorder" render={()=><SaveOrder data={this.state.data}/>} />
</div>
</Router>
<Map />
<Footer />
</div>
You can use this.props.history.push('/') if your Header component is passed to the withRouter HOC.
withRouter allows you to get history in component props.
So... in Header component you should import withRouter HOC
import { withRouter } from 'react-router-dom';
and export your Header component like this:
export default withRouter(Header);
You can find more info about programmatic navigation here https://tylermcginnis.com/react-router-programmatically-navigate/
an example of what you want to do is found at the end of the post :)
move Header inside Router, only the component that are inside <Router> that can use any of react-router's apis.
the code would look like this:
<div>
<Router data={this.state.data}>
<div>
<Header order={this.order} />
<Menu data={this.state.data} />
<Route exact path="/" component={Home} />
<Route exact path="/post" component={PostList} />
<Route path="/showpost/:slug" component={ShowPost} />
<Route path="/page/:slug" component={ShowPage} />
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Route path="/forgotpassword" component={Forgot} />
<Route path="/password/reset/:token" component={Reset} />
<Route path="/logout" component={Logout} />
<Route path="/user" component={User} />
<Route
path="/saveorder"
render={() => <SaveOrder data={this.state.data} />}
/>
</div>
</Router>
<Map />
<Footer />
</div>

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>
);

Categories

Resources