Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I have this error that say "Cannot update a components while rendering a different component" when I run react.js code

I have the error "Warning: Cannot update a component (App) while rendering a different component (Car). To locate the bad setState() call inside Car" when I run my code. If I take out the function removeFromCart(p), the code is good, but if this function is in App, the code is broken.

function App() {

  const [product, setProduct] = useState({
    product: data.products,
    cartItem:[],
    size: "",
    sort: ""
  })

  const removeFromCart = (p) => {
    //Copy the recent products in cart
    let cartItems = product.cartItem;
    //Take out the product you choose in cart
    setProduct({
      ...product,
      cartItem: cartItems.filter(x=>x._id!==p._id)
    });
  }

  //Add item to the product.cartItem
  const addToCart = (p) => {
    //Copy what does the cart has
    const cartItems = product.cartItem;
    let inCart = false;

    //To check the item you click is in the cart or not
    cartItems.forEach((item) => {
      if (item._id === p._id) {
        //If in the cart, the item count +1
        item.count++;
        //inCart become true to tell next statement the item you click already in in the cart,
        //WE don't need to push a need item to the cart.
        inCart = true;
      } 
    })
    //If the item you click is not in the cart, 
    //Pushing this to the cart, and set this item's count in 1. 
    if (!inCart) {
      cartItems.push({...p, count:1})
    }

    //To renew the cartItem in the product state.
    setProduct({...product, cartItem:cartItems});
  }


  //To show the items which has the size you choose
  const sizeProducts = (e) => {
    //value is the size you choose
    let { value } = e.target
    //s is the sort parameter you choose
    let s = product.sort;

    //If you didn't choose any size, show all product.
    if (value === "") {
      setProduct({ size:"", sort:s, product: data.products });
    } else {
      //If you choose any size, show the product that have the size you choose,
      //and sort it will the sort parameter yuou choose
      setProduct({
        size: value,
        sort:s,
        product: data.products.filter(p => 
          p.availableSizes.indexOf(value) >= 0
        ).sort((a, b) => 
          s === "lowest" ? ((a.price > b.price) ? 1 : -1) :
            s === "highest" ? ((a.price < b.price) ? 1 : -1) :
              ((a._id > b._id) ? 1 : -1)
        )
      });
    }
  }

  const sortProducts = (e) => {
    //The value is the sort parameter you choose
    let { value } = e.target;
    //The curr is the product after yiu choose the parameter in the size
    let curr = product.product;
    
    //Sort product
      setProduct({
        sort: value,
        product: curr.sort((a, b) => 
          value === "lowest" ? ((a.price > b.price) ? 1 : -1) :
            value === "highest" ? ((a.price < b.price) ? 1 : -1) :
              ((a._id > b._id) ? 1 : -1)
        )
      });
    }
    
  
  return (
    <div >
      <Grid xs={ 12 }>
        <Navigation />
      </Grid>
      <Grid container>
        <Grid xs={0} sm={2}></Grid>
        <Grid container xs={12} sm={8}>
          <Grid item xs={12}>
            <Filter count={product.product.length}
              size={product.size}
              sort={product.sort}
              sizeProducts={sizeProducts}
              sortProducts={ sortProducts}
            ></Filter>
          </Grid>
          <Product
            products={product.product}
            addToCart={  addToCart }
          ></Product>
        </Grid>
        <Grid xs={0} sm={2}></Grid>
      </Grid>
      
      <div className="cartSection">
        <Car cartItems={product.cartItem}
          removeFromCart={ removeFromCart } />
      </div>

    </div>
  );
}

Car component:

export default class Car extends Component {

    render() {
        const { cartItems } = this.props;
        return (
            <Grid container className="cart">
                <Grid container xs={12}>
                     <Grid xs={12} sm={6} md={3} >
            <div>
                {cartItems.length === 0 ?
                    (<div>Cart Empty</div>) :
                    (<div>You have {cartItems.length} in cart</div>)
                }
                
                    {cartItems.map(item => (
                        <div key={ item._id } className="cartItem">
                            <img src={item.image} alt="" />
                            <div className="info">
                                <div>
                                    { item.title }
                                </div>
                                <div>
                                    <span>{item.count} X ${item.price}</span>
                                    <Button
                                        variant="contained"
                                        color="primary"
                                        onClick={ this.props.removeFromCart(item) }
                                    >Remove</Button>
                                </div>  
                            </div>
                        </div>
                    ))}
                </div>
                   </Grid>
             </Grid>
        </Grid>
        )
    }
}

Error:

index.js:1 Warning: Cannot update a component (`App`) while rendering a different component (`Car`). To locate the bad setState() call inside `Car`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
    at Car 
    at div
    at div
    at App 
like image 622
Lee Alex Avatar asked Sep 01 '26 21:09

Lee Alex


1 Answers

doing

onClick={ this.props.removeFromCart(item) } 

will call this.props.removeFromCart immediately, causing the App component to update while rendering Car ( because it's updating its state ), replace it with :

// in the Car component
onClick={ () => this.props.removeFromCart(item) } 

see the snippet below for the difference , the first one will call greet even before you click on the button :

const App = () => {
  const greet = (msg) => { console.log('hello, ', msg); }
  
  return <div>    
    <button onClick={greet('world')}>click me</button>
    <button onClick={() => greet('world 2')}>click me</button>
  </div>
}

ReactDOM.render(<App />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
like image 58
Taki Avatar answered Sep 04 '26 10:09

Taki



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!