I'm building a winery themed shopping app in React and I'm using functional components. I have 12 products (wines) displayed on one page, and I want to make a separate page for each wine when the user clicks on it.
This is how I handled routes:
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products wines={products}/>} />
<Route path="/contact" element={<Contact />} />
<Route path="/cart" element={<Cart />} />
{wines.map((wine) => (
<Route key={wine.id} path={`/shop/${wine.id}`} element={<Item item={wine} />}/>
))}
</Routes>
</BrowserRouter>
I mapped through all of the wines and created a separate route for each of them, and sent a particular wine as a prop to each "Item" component.
Item component looks like this:
const Item = (item) => {
return (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={item.name} src={item.image} />
<h1 className="item_name">{item.name}</h1>
<h3 className="item_price">{item.price}</h3>
</div>
<Footer />
</>
)
When I console log "item" in this component, I get the specific wine and I can see all of its attributes (name, price, image URL), but when I try to access those attributes in order to display them (item.name, item.image, item.price), the console logs "undefined".
How can i fix this?
You've passed a item prop to the Item component.
<Item item={wine} />
And then named the props object item in the Item component.
const Item = (item) => { ... }
Either rename to props and correctly access props.item.xxx
const Item = (props) => {
const { item } = props;
return (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={item.name} src={item.image} />
<h1 className="item_name">{item.name}</h1>
<h3 className="item_price">{item.price}</h3>
</div>
<Footer />
</>
);
}
or destructure item directly
const Item = ({ item }) => (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={item.name} src={item.image} />
<h1 className="item_name">{item.name}</h1>
<h3 className="item_price">{item.price}</h3>
</div>
<Footer />
</>
);
An optimization I'd suggest is to declare a single route with the wine id as a route path param, and then access the wines array in Item.
Example:
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products wines={products}/>} />
<Route path="/contact" element={<Contact />} />
<Route path="/cart" element={<Cart />} />
<Route path="/shop/:wineId" element={<Item />} />
</Routes>
</BrowserRouter>
...
import { useParams } from 'react-router-dom';
const Item = () => {
const { wineId } = useParams();
const wine = wines.find(wine => wine.id === wineId);
if (!wine) return <div>No wine found.</div>;
return (
<>
<Header />
<div className="item_container">
<img className="item_image" alt={wine.name} src={wine.image} />
<h1 className="item_name">{wine.name}</h1>
<h3 className="item_price">{wine.price}</h3>
</div>
<Footer />
</>
);
}
Please check null and empty array for "wines" first , if not null then map through "wines"