Routing: passing a prop from one page to another

Viewed 93

I'm working on an Ecommerce site. Right now I'm linking between all the pages correctly.

On the page below, I'm mapping over all items from the API.

What I'm trying to do now: When a user clicks an item, how can I make the new page ("Item", currently blank) populate all the info just for that one clicked item? My guess is that you include and pass props in , specifically the id that can then be referenced in the Item page, but it's not working.

What is the best approach to implementing this? Feedback greatly appreciated.

"Shop page"

import React, { useState, useEffect } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
import {Link} from 'react-router-dom';

function Shop() {

const [products, setProducts] = useState([]);
const [filterProducts, setFilteredProducts] = useState([]);
const [item, setItem] = useState('');
const [currentSort, setCurrentSort] = useState('');
const [loading, setLoading] = useState(false);

useEffect(async () => {
  fetchItems();
}, [])

const fetchItems = async () => {
  const data = await fetch('https://fakestoreapi.com/products');
  const items = await data.json();
  setProducts(items)
  setLoading(true)
}
function priceUSD(change){
  return change.toFixed(2)
}

useEffect(() => {
  const filteredItems = products.filter((a) => {
    if (item === '') {return a} else {return a.category === item}
  });
  setFilteredProducts(filteredItems);
}, [item, products])

 useEffect(() => {
  if (currentSort === '') {
    return
  }
  const sortedItems = filterProducts.sort((a, b) => {
    return currentSort === 'ASE' ? a.price - b.price : b.price - a.price
  });
  setFilteredProducts([...sortedItems]);
}, [currentSort])

console.log(products)
    return (
        <div>
          <div className="itemSort">
            <p onClick={() => setItem("")}>All items</p>
            <p onClick={() => setItem("men clothing")}>Men clothing</p>
            <p onClick={() => setItem("women clothing")}>Women clothing</p>
            <p onClick={() => setItem("jewelery")}>Jewelery</p>
            <p onClick={() => setItem("electronics")}>Electronics</p>
          </div>

          <div className="itemSort">
            <p>Order by price</p>
            <p onClick={() => setCurrentSort('DESC')}>Highest</p>
            <p onClick={() => setCurrentSort('ASE')}>Lowest</p>
          </div>

            <div className="gridContainer">
              {loading ?
                          (filterProducts.map((a, index) => (
                            <Link to={`/Item/${a.id}`}>
                              <div key={index} className="productStyle">
                                <img src={a.image} className="productImage"></img>
                                <p>{a.title}</p>
                                <p>${priceUSD(a.price)}</p>
                              </div>
                            </Link>
                        )))  : (<ReactBootStrap.Spinner className="spinner" animation="border" />)
                        }
            </div>
        </div>
    )
}

export default Shop;

"Item page"

import React, { useState } from 'react';
import './../App.css';

function Item() {
    return (
      <div className="App">
        <h2>Item</h2>
        <h2></h2>
      </div>
    );
}

export default Item;

"Router"

import React, { useState } from 'react';
import './App.css';
import Nav from './Nav';
import Shop from './Components/Shop';
import Info from './Components/Info';
import Cart from './Components/Cart';
import Item from './Components/Item';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';

function App() {
    return (
      <Router>
        <div className="App">
          <Nav />

          <Route path="/" exact component={Shop} />
          <Route path="/Info" component={Info} />
          <Route path="/Cart" component={Cart} />
          <Route path="/Item" component={Item} />

        </div>
      </Router>
    )
}

export default App;
1 Answers

If I understand correctly you want to populate a new item page with data for the selected item.

To do this in your routes you need to add a id for item.

<Route path="/Item/:id" component={Item} />

Then in your shop page as you have already done you need to navigate to item/id for example:

<div className="gridContainer">
          {loading ?
                      (filterProducts.map((a, index) => (
                        <Link to={`/Item/${a.id}`}>
                          <div key={index} className="productStyle">
                            <img src={a.image} className="productImage"></img>
                            <p>{a.title}</p>
                            <p>${priceUSD(a.price)}</p>
                          </div>
                        </Link>
                    )))  : (<ReactBootStrap.Spinner className="spinner" animation="border" />)
                    }
        </div>

Then finally in the item component you can access the id from the ULR using props specifically:

this.props.match.params

In this match.params is an object create by react-router-dom. If you have react dev tools extension installed in your browser you can view the components tab and see what properties this object has.

Specifcally in order to get id you need to access id so it would be something like:

const { id: itemId } = this.props.match.params;

The finally all you need to do is get the data for the item using the id. Once you have the data all you then need to do is set the state and then use the state to populate the UI or form.

Related