React Router: Link and Route not passing state to Component
I’m building an online shopping app with React, Redux, and React Router. On the home page, all items are displayed. I want users to be able to click on an image and be taken to a page with item details for that item.
Here's how I’m trying to do that:
- In App.js, I’m using BrowserRouter, Route, and Switch for routing
- In Home.js, I’m using react-router's Link to link an image on the Home page to an item details page; the Link is supposed to pass the ID to the Item component as state (see the Home.js code below)
- Item.js is supposed to render an items detail page. The ID of the item will be passed to the Item component, which will render the details for that item.
This seems simple, and I’ve seen a lot of discussion about this on SO and across the web. Here are some that I have already tried:
Display item details after clicking Link in React Router
React router how to click thru to detail components
Passing values through React-Router v4 <Link />
Tyler McGinnis - Pass props to React Router's Link component
Medium - How to pass props to React routes components
I’m able to get the URL to change to correspond to the item’s ID, but I can’t get the Item component to render with the right information, and sometimes I get errors depending on the method I’m using. I hard coded the words "Item Component" inside a div in Item.js, and that will render when I click on the images from the Home page. Otherwise, nothing will render or I receive the two following TypeErrors:
App.js:
<Route path="/products" render={(props) => (<Item {...props} id={this.props.location.id} />) }/>
export default withRouter(App);
<App />
is wrapped in <BrowserRouter>
in index.js.
I receive the following error when clicking on an image from the home page:
TypeError: Cannot read property 'props' of undefined
When the above “render” code is removed from and replaced with “component={ Item }”, I receive this error from Item.js: TypeError: Cannot read property 'location' of undefined
Here are my other code snippets:
Item.js:
class Item extends React.Component {
constructor() {
super();
this.state = {
item: this.props.location.state
}
}
render() {
let item = this.state.item;
return (
<div className="item" key={item.id}>
<div className="item-image">
<img src={item.img} alt={item.title} />
</div>
<div className="card-component">
<span className="item-title">{item.title}</span>
<p className="item-price"><b>${item.price}</b></p>
<p className="item-desc">{item.desc}</p>
</div>
</div>
);
}
}
Home.js (where all items are displayed), the item details page is linked like so:
<Link to =
{{ pathname: `/products/${item.category}`,
search: `?id=${item.id}`,
state: {id: `${item.id}`} }}
component={ Item }>
<img src={item.img} alt={item.title} />
</Link>
UPDATE
I have wrapped the <Item/>
component in withRouter()
.
In Item.js, if I set the state in the constructor as { item: this.props.location.state }
, nothing renders as it should (only a dollar sign is on the screen, since the price section contains a hard coded dollar sign).
I tried setting the Item.js state to null
in the constructor, then calling this.setState
with { item: this.props.location.state }
in componentDidMount()
. When I do this, I receive the following error:
TypeError: Cannot read property 'img' of null
Also, if I leave the render={(props) => (<Item {...props} id={this.props.location.id} />) }
in the <Route>
in App.js
, I receive this error:
TypeError: Cannot read property 'props' of undefined
If I change <Route>
back to component={ Item }
, and the Item.js constructor state is set to { item: this.props.location.state }
, just the dollar sign renders.
UPDATE: include App.js and Routes.js code
App.js
import React from 'react';
import {
BrowserRouter as Router,
withRouter,
Switch
} from 'react-router-dom';
import './App.css';
import Navbar from './components/Navbar';
import Footer from './components/footer/Footer';
import { Routes } from './constants/Routes';
class App extends React.Component {
render() {
return (
<Router>
<div className="App">
<Navbar />
<Switch>
{ Routes }
</Switch>
<Footer />
</div>
</Router>
);
}
}
export default withRouter(App);
Routes.js
import React from 'react';
import { Route } from 'react-router-dom';
import Home from '../components/Home';
import Item from '../components/shopping/Item';
import Cart from '../components/cart/Cart';
import OrderStatus from '../components/footer/OrderStatus';
import GiftCards from '../components/footer/GiftCards';
import ReturnsExchanges from '../components/footer/Returns-Exchanges';
import Contact from '../components/footer/Contact';
export const Routes = <div>
<Route exact path="/" component={ Home } />
<Route path="/products" component={ Item }/>
<Route path="/cart" component={ Cart } />
<Route path="/order-status" component={ OrderStatus } />
<Route path="/gift-cards" component={ GiftCards } />
<Route path="/returns-exchanges" component={ ReturnsExchanges } />
<Route path="/contact" component={ Contact } />
</div>
App
component withwithRouter
? – vipulpBrowserRouter
. Checkout my answer below. Hope it helps. Also, will be helpful to see yourApp.js
code. – vipulpApp.js
code. I will edit my question and include it at the bottom. – Jenna