简体   繁体   English

当点击 React 中的按钮时,组件会渲染两次

[英]When a button in React is clicked, the component renders twice

I'm pretty new to React, and I'm making an ecommerce website for practice.我对 React 很陌生,我正在制作一个电子商务网站以供练习。 I have a cart component that dynamically renders cart items from an API, but I narrowed the problem 100% down to the front end.我有一个购物车组件,可以从 API 动态呈现购物车项目,但我将问题 100% 缩小到前端。 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) CartCard.jsx(/api/delete 删除后返回购物车的 json object。删除在 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:购物车.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:配置文件.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应用程序.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;

Thanks for your help谢谢你的帮助

This for loop might be the issue:这个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])

Keep in mind that setState in react is asynchronous.请记住,react 中的setState是异步的。 What it means:这是什么意思:

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

Try changing your for loop into that:尝试将您的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}/>])
}

As @deaponn mentioned, useState is asynchronous.正如@deaponn提到的, useState是异步的。

Your for loop in setCartComp is called n times. setCartComp中的 for 循环被调用 n 次。 Alternatively what about using javascript's map function:或者如何使用javascript的map function:

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]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM