Events and adding to cart

You've done some amazing work getting to this point! You've created your own Product component and we're now rendering products on the page dynamically. You also know how to change the state of a component. Now it's time to take a look at events and specifically, how we can emit an event to add a product to the cart.

Learning Objectives

Learn how events work

You'll notice that we've got the 'Full details' and the 'Add to cart' buttons, but neither of them work because we haven't wired them up. Let's rectify that and wire up the Add to cart button so it adds the Product to the cart.

Step 1

In your Product component add an event listener and event handler called addToCart to the <button> element. When we click on the button we'll see that product logged in the console. Below are the code snippets. Use the Img component as a reference for how to add this to your Product component.

const addToCart = (product) => {
    console.table(product)
}

<button onClick={addToCart(props.product)}>
    Add to cart
</button>

Problem solving

Now we have a problem to solve. In the data that we import from our products.json file there is a property called 'cart' that is an Array. We need to push the product into the cart array, but the cart exists in the data object that belongs to the App component that is outside the scope of our Product component.

There are a number of ways to solve this and two examples are:

Using Redux at this point is a little overkill as there are only three components in our app. For that reason, let's pass a function down the component tree into the child component from the parent. We'll incorporate Redux later when our app becomes more complex

Let's visualise the process in a diagram:

Data Flowing DownPassing Data Up
data flowing down component tree
data flowing up the component tree

So far we have only passed data down the component tree in one direction. Now we are going to go in the opposite direction and pass data up the component tree. To do this we are going to pass our parent setState function into a child component for it to call with the values it has within it.

Passing Data Up the Component tree

Create a reactive variable within the App component that will be the cart.

import { useState } from 'react'
import data from './products.json'
import { Product } from './Product'

function App() {
  const [cart, setCart] = useState(data.cart)

  const addToCart = product => {
    setCart([...cart, product])
  }

    console.log(cart)
  return (
    <div className="App">
      {data.products.map(product => <Product product={product} addToCart={addToCart} />)}
    </div>
  );
}

export default App

Our updates are:

  1. import useState from 'react'
  2. create a reactive variable called cart and setter called setCart
  3. create an addToCart function that will receive a product and add it to the array of items already in the cart
  4. pass the addToCart function down into the Product component

Now we can call this within the Product component like this. You can remove the Product component's version of addToCart, we are calling the addToCart function passed down to us from the App parent component with our instance of a product.

<button onClick={()=>props.addToCart(props.product)}>Add to cart</button>

Assignment - Coding challenge

Does it work?

The problem we have now is that you can continue to click the button and the product will get added to the cart array over and over again.