I’m pretty new to React, and I’m making an ecommerce website for practice. I have a cart component that dynamically renders cart items from an API, but I narrowed the problem 100% down to the front end. On the initial render, it works fine, everything that is in the database cart appears, however after I press the “Delete from Cart” button on a cart item, each cart item doubles.
CartCard.jsx (/api/delete returns a json object of the cart AFTER deletion. deletion is handled in the api)
JavaScript
x
51
51
1
import React from "react";
2
import CartCardCSS from "./CartCard.module.css";
3
4
export default function CartCard(props) {
5
const passCart = props.passCart;
6
7
function deleteFromCart(e) {
8
e.preventDefault();
9
10
const item = {
11
id: props.id,
12
mainText: props.mainText,
13
price: props.price,
14
type: props.type
15
}
16
const user = {
17
username: props.username
18
}
19
const compoundEntity = {
20
theContent: item,
21
theUser: user
22
}
23
24
25
const requestOptions = {
26
method: "POST",
27
headers: {"Content-Type" : "application/json"},
28
body: JSON.stringify(compoundEntity)
29
}
30
31
32
fetch("/api/delete", requestOptions)
33
.then(response => response.json())
34
.then(response => {
35
passCart(response)
36
console.log(response)
37
})
38
39
40
}
41
42
return (
43
<div className={CartCardCSS.card}>
44
<img src={props.image} className={CartCardCSS.itempicture} alt="item picture"/>
45
<h3 className={CartCardCSS.subitem}>{props.mainText}</h3>
46
<h4 className={CartCardCSS.subitem}>{props.price}</h4>
47
<button onClick={deleteFromCart} className={`${CartCardCSS.subitem} ${CartCardCSS.button}`} type="button">Remove From Cart</button>
48
</div>
49
)
50
}
51
Cart.jsx:
JavaScript
1
35
35
1
import React, {useEffect, useState} from "react";
2
import CartCard from "./CartCard";
3
4
import CpuPicture from "./img/cpu.jpg";
5
import GpuPicture from "./img/gpu.jpg";
6
7
8
export default function Cart(props) {
9
10
const cart = props.cart;
11
const username = props.username;
12
const passCart = props.passCart;
13
const [arrCart, setArrCart] = useState(Object.values(cart))
14
const [cartComp, setCartComp] = useState()
15
16
useEffect(() => {
17
18
console.log(cart)
19
setArrCart(Object.values(cart))
20
21
for(let i = 0; i < arrCart.length; i++) {
22
setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={arrCart[i].mainText} price={arrCart[i].price} type={arrCart[i].type} image={arrCart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
23
}
24
25
}, [cart])
26
27
return (
28
<div>
29
<h2 >Cart:</h2>
30
{cartComp}
31
</div>
32
)
33
34
}
35
Profile.jsx:
JavaScript
1
37
37
1
import React from "react";
2
import Cart from "./Cart";
3
import Navbar from "./Navbar";
4
5
import {useNavigate} from "react-router-dom";
6
7
8
export default function Profile(props) {
9
const username = props.username;
10
const isLoggedIn = props.isLoggedIn;
11
const cart = props.cart;
12
const passCart = props.passCart;
13
let navigate = useNavigate();
14
const routeChange = () => {
15
16
let path = "/login";
17
navigate(path);
18
}
19
20
21
if (isLoggedIn) {
22
return (
23
<div>
24
<Navbar />
25
<h1>{username}</h1>
26
<Cart passCart={passCart} username={username} cart={cart} />
27
28
</div>
29
30
)
31
} else {
32
33
routeChange();
34
}
35
36
}
37
App.jsx
JavaScript
1
49
49
1
import React, {useState} from "react";
2
import './App.css';
3
import Login from "./components/Login";
4
import Signup from "./components/Signup";
5
import Home from "./components/Home";
6
import Profile from "./components/Profile";
7
import Card from "./components/Card";
8
import GpuPicture from "./components/img/gpu.jpg";
9
import CpuPicture from "./components/img/cpu.jpg";
10
11
import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom";
12
13
function App() {
14
const [username, setUsername] = useState('');
15
const [cart, setCart] = useState('');
16
const [isLoggedIn, setIsLoggedIn] = useState(false)
17
18
function passUsername(items) {
19
setUsername(items);
20
}
21
function passCart(items) {
22
setCart(items);
23
24
}
25
function passIsLoggedIn(items) {
26
setIsLoggedIn(items);
27
28
}
29
30
31
32
return (
33
<div className="App">
34
<BrowserRouter>
35
<Routes>
36
<Route path="/" element={<Navigate to="/login"/>} />
37
<Route path="/login" element={<Login passIsLoggedIn={passIsLoggedIn} passUsername={passUsername} passCart={passCart}/>}/>
38
<Route path="/signup" element={<Signup />}/>
39
<Route path="/home" element={<Home passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn} />} />
40
<Route path="/profile" element={<Profile passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn}/>} />
41
</Routes>
42
</BrowserRouter>
43
</div>
44
);
45
}
46
47
export default App;
48
49
Thanks for your help
Advertisement
Answer
This for
loop might be the issue:
JavaScript
1
11
11
1
useEffect(() => {
2
3
console.log(cart)
4
setArrCart(Object.values(cart))
5
6
for(let i = 0; i < arrCart.length; i++) {
7
setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={arrCart[i].mainText} price={arrCart[i].price} type={arrCart[i].type} image={arrCart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
8
}
9
10
}, [cart])
11
Keep in mind that setState
in react is asynchronous. What it means:
JavaScript
1
4
1
console.log(arrCart) // previous state
2
setArrCart(Object.values(cart))
3
console.log(arrCart) // still previous state
4
Try changing your for
loop into that:
JavaScript
1
4
1
for(let i = 0; i < cart.length; i++) {
2
setCartComp(arr => [arr, <CartCard key={i} id={i} passCart={passCart} username={username} mainText={cart[i].mainText} price={cart[i].price} type={cart[i].type} image={cart[i].type === "cpu" ? CpuPicture : GpuPicture}/>])
3
}
4