Video Walkthrough
subscribe on youtube for more content.
Article Explanation of Hooks
In this article, we will use hooks to create a video game shop and shopping cart.
First, I will show an example of how to use the useState hook.
import React, { useState } from "react";
const Shop = () => {
const [open, setOpen] = useState(true);
console.log(open)
const closeStore = () => {
setOpen(false)
}
return(
<div>
<input type="submit" value="close" onClick={() => closeStore()} />
</div>
)
}
export default Shop;
In this example, open is a key that holds the useState argument as its value. useState(true), open = true.
setOpen is a function that takes a value as an argument.
setOpen will set open to the new value passed to setOpen.
setOpen(false), sets open = false
This shows a button that can be clicked in order to change the value of open from true to false.
Let's try a more complex use case.
In App.js we will return a div with our soon to be created Shop component:
import React from "react";
import Shop from "./shop/Shop";
function App() {
return (
<div>
<Shop />
</div>
);
}
export default App;
We will create the shop component next. Create a folder in src named shop. Then create a file in that folder named Shop.js
The finished Shop.js code is at the bottom of the article.
We are going to return an empty functional component to get us started:
import React, { useState, useEffect } from "react";
const Shop = () => {
return <div />
}
export default Shop;
Let's add our inventory as an array labeled items:
const Shop = () => {
const items = [
{
id: 1,
name: "overwatch",
price: 20,
},
{
id: 2,
name: "minecraft",
price: 32,
},
{
id: 3,
name: "fortnite",
price: 51,
},
];
return <div />
}
We are only selling these three video games. We need to display them. So, we will create a new formatted array called listItems using .map(). Now, we should return listItems:
const listItems = items.map((el) => (
<div key={el.id}>
{`${el.name}: $${el.price}`}
<input type="submit" value="add" onClick={() => addToCart(el)} />
</div>
));
return(<div>{listItems}</div>)
Above items, we will create our first useState hook:
const [cart, setCart] = useState([]);
The const cart is where we will hold our cart state. We can call setCart() and pass in the state changes we want to make to cart. Let's create our addToCart function using setCart:
const addToCart = (el) => {
setCart([...cart, el]);
};
addToCart takes the element selected and adds it to the cart array.
We are going to display the cart, in our app, under our store. First, make a new formatted array from the cart array:
const cartItems = cart.map((el) => (
<div key={el.id}>
{`${el.name}: $${el.price}`}
<input type="submit" value="remove" onClick={() => removeFromCart(el)} />
</div>
));
We can create our removeFromCart function using the filter method. note* We will make a copy of the cart state before filtering:
const removeFromCart = (el) => {
let hardCopy = [...cart];
hardCopy = hardCopy.filter((cartItem) => cartItem.id !== el.id);
setCart(hardCopy);
};
Change the return statement to include cartItems:
return (
<div>
STORE
<div>{listItems}</div>
<div>CART</div>
<div>{cartItems}</div>
</div>
);
Finally, we will keep track of the total using useState and useEffect:
const [cartTotal, setCartTotal] = useState(0);
useEffect(() => {
total();
}, [cart]);
const total = () => {
let totalVal = 0;
for (let i = 0; i < cart.length; i++) {
totalVal += cart[i].price;
}
setCartTotal(totalVal);
};
The useEffect hook contains an arrow function. Inside the arrow function, we call our total function.
The second argument in useEffect is the dependency array containing [cart].
useEffect will detect changes in the variables named within its dependency array. When it detects a change, it will run again.
Every time an item is added or removed from the cart, useEffect will detect a change in cart and run the total function.
Finally, place total in your return:
import React, { useState, useEffect } from "react";
const Shop = () => {
const [cart, setCart] = useState([]);
const [cartTotal, setCartTotal] = useState(0);
const items = [
{
id: 1,
name: "overwatch",
price: 20,
},
{
id: 2,
name: "minecraft",
price: 32,
},
{
id: 3,
name: "fortnite",
price: 51,
},
];
useEffect(() => {
total();
}, [cart]);
const total = () => {
let totalVal = 0;
for (let i = 0; i < cart.length; i++) {
totalVal += cart[i].price;
}
setCartTotal(totalVal);
};
const addToCart = (el) => {
setCart([...cart, el]);
};
const removeFromCart = (el) => {
let hardCopy = [...cart];
hardCopy = hardCopy.filter((cartItem) => cartItem.id !== el.id);
setCart(hardCopy);
};
const listItems = items.map((el) => (
<div key={el.id}>
{`${el.name}: $${el.price}`}
<input type="submit" value="add" onClick={() => addToCart(el)} />
</div>
));
const cartItems = cart.map((el) => (
<div key={el.id}>
{`${el.name}: $${el.price}`}
<input type="submit" value="remove" onClick={() => removeFromCart(el)} />
</div>
));
return (
<div>
STORE
<div>{listItems}</div>
<div>CART</div>
<div>{cartItems}</div>
<div>Total: ${cartTotal}</div>
</div>
);
};
export default Shop;
Watch the video for more! Next, we will refactor this code to use Redux. After that, we will start making http requests using the fetch api and redux-thunk. Finally, we will convert the project to redux-saga. The videos are up on youtube already Youtube Channel Link and the articles are on their way!
Top comments (4)
Some quick notes:
1) You don't need
useEffect
noruseState
to grab the total value in the cart. You can grab that value by using the cart already in state.2) Anytime updating state which depends on the previous state its a good practice to use functional updates.
Refactored it a bit to address both points mentioned before:
I agree. This is how Iโd do it in practice. I wanted to explain useEffect in the article so I created a use case where I could use it as well as itโs dependency array. Iโll heart this so people can see this as well.
how to stop adding same product in cart again and again using useState
Nice tutorial, easy for beginners to understand useState and useEffect, Tiagos implementation is superb but may confuse beginners.