单击React中的按钮时,组件将渲染两次



我是React的新手,我正在制作一个电子商务网站进行练习。我有一个从API动态呈现购物车项目的购物车组件,但我将问题100%缩小到了前端。在最初的渲染中,它工作得很好,数据库车中的所有内容都会出现,但在我按下";从购物车中删除";按钮,每个购物车项目加倍。

CartCard.jsx(/api/delete在删除后返回cart的json对象。删除在api中处理(

import React from "react";
import CartCardCSS from "./CartCard.module.css";
export default function CartCard(props) {
const passCart = props.passCart;
function deleteFromCart(e) {
e.preventDefault();
const item = {
id: props.id,
mainText: props.mainText,
price: props.price,
type: props.type
}
const user = {
username: props.username
}
const compoundEntity = {
theContent: item,
theUser: user
}

const requestOptions = {
method: "POST",
headers: {"Content-Type" : "application/json"},
body: JSON.stringify(compoundEntity)
}

fetch("/api/delete", requestOptions)
.then(response => response.json())
.then(response => {
passCart(response)
console.log(response)
})

}

return (
<div className={CartCardCSS.card}>
<img src={props.image} className={CartCardCSS.itempicture} alt="item picture"/>
<h3 className={CartCardCSS.subitem}>{props.mainText}</h3>
<h4 className={CartCardCSS.subitem}>{props.price}</h4>
<button onClick={deleteFromCart} className={`${CartCardCSS.subitem} ${CartCardCSS.button}`} type="button">Remove From Cart</button>
</div>
)
}

Cart.jsx:

import React, {useEffect, useState} from "react";
import CartCard from "./CartCard";
import CpuPicture from "./img/cpu.jpg";
import GpuPicture from "./img/gpu.jpg";

export default function Cart(props) {
const cart = props.cart;
const username = props.username;
const passCart = props.passCart;
const [arrCart, setArrCart] = useState(Object.values(cart))
const [cartComp, setCartComp] = useState()
useEffect(() => {
console.log(cart)
setArrCart(Object.values(cart))

for(let i = 0; i < arrCart.length; i++) {
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}/>])
}
}, [cart])
return (
<div>
<h2 >Cart:</h2>
{cartComp}
</div>
)
}

Profile.jsx:

import React from "react";
import Cart from "./Cart";
import Navbar from "./Navbar";
import {useNavigate} from "react-router-dom";

export default function Profile(props) {
const username = props.username;
const isLoggedIn = props.isLoggedIn;
const cart = props.cart;
const passCart = props.passCart;
let navigate = useNavigate();
const routeChange = () => {
let path = "/login";
navigate(path);
}

if (isLoggedIn) {
return (
<div>
<Navbar />
<h1>{username}</h1>
<Cart passCart={passCart} username={username} cart={cart} />

</div>

)
} else {

routeChange();
}
}

App.jsx

import React, {useState} from "react";
import './App.css';
import Login from "./components/Login";
import Signup from "./components/Signup";
import Home from "./components/Home";
import Profile from "./components/Profile";
import Card from "./components/Card";
import GpuPicture from "./components/img/gpu.jpg";
import CpuPicture from "./components/img/cpu.jpg";
import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom";
function App() {
const [username, setUsername] = useState('');
const [cart, setCart] = useState('');
const [isLoggedIn, setIsLoggedIn] = useState(false)
function passUsername(items) {
setUsername(items);
}
function passCart(items) {
setCart(items);
}
function passIsLoggedIn(items) {
setIsLoggedIn(items);
}

return (
<div className="App">
<BrowserRouter>
<Routes>
<Route path="/" element={<Navigate to="/login"/>} />
<Route path="/login" element={<Login passIsLoggedIn={passIsLoggedIn} passUsername={passUsername} passCart={passCart}/>}/>
<Route path="/signup" element={<Signup />}/>
<Route path="/home" element={<Home passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn} />} />
<Route path="/profile" element={<Profile passCart={passCart} cart={cart} username={username} isLoggedIn={isLoggedIn}/>} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;

感谢您的帮助

如@deaponn所述,useState是异步的。

setCartComp中的for循环被调用了n次。或者,使用javascript的map函数:

useEffect(() => {
console.log(cart);
// map transforms the array into an array of another type (in this case CartCard instances)
setCartComp(Object.values(cart).map((item, index) =>
<CartCard key={index} id={index}
passCart={passCart}
username={username}
mainText={item.mainText}
price={item.price}
type={item.type}
image={item.type === "cpu" ? CpuPicture : GpuPicture} />));
}, [cart]);

这个for循环可能是问题所在:

useEffect(() => {
console.log(cart)
setArrCart(Object.values(cart))

for(let i = 0; i < arrCart.length; i++) {
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}/>])
}
}, [cart])

请记住,react中的setState是异步的。意思是:

console.log(arrCart) // previous state
setArrCart(Object.values(cart))
console.log(arrCart) // still previous state

尝试将for循环更改为:

for(let i = 0; i < cart.length; i++) {
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}/>])
}

最新更新