Search code examples
javascriptreactjsreact-class-based-component

The react state is not changing when I am trying to change it


enter image description here

I have a state isCartACtive when I am trying to close it running

// Function that will show the cart
  handleCartActive(){
    console.log("cart active",this.state.isCartActive);
    this.setState(prevState =>({
      isCartActive:!prevState.isCartActive
    }))
  }

the code dont give any error neither it is changing state

OverlayCart.jsx

import React, { Component } from 'react';
import { OverlayCartContainer,OverlayCartHeader,TotalContainer,
  ActionSection,ViewBagButton,CheckoutButton,CartCount,NavbarItem,OverlayContainerWrapper,
  NavbarItemIcon } from './OverlayCartStyle';
import { Link } from 'react-router-dom'
import { connect } from 'react-redux';
import { OverlayCartbody } from '../../';


export class OverlayCart extends Component {

  constructor(){
    super();
    this.state={
      isCartActive:false,
      ref: React.createRef(null),
    }
  }

  handleHideDropdown = (event) => {
    if (event.key === 'Escape') {
      this.setState({ isCartActive: false });
    }
  }

  handleClickOutside = (event) => {
    if (this.state.ref.current && !this.state.ref.current.contains(event.target)) {
      this.setState({ isCartActive: false });
    }
  }

  componentDidMount() {
    document.addEventListener('keydown', this.handleHideDropdown, true);
    document.addEventListener('click', this.handleClickOutside, true);
  }

  componentWillUnmount(){
    document.removeEventListener('keydown', this.handleHideDropdown, true);
    document.removeEventListener('click', this.handleClickOutside, true);
  }

  // Function that will show the cart
  handleCartActive(){
    console.log("cart active",this.state.isCartActive);
    this.setState(prevState =>({
      isCartActive:!prevState.isCartActive
    }))
  }

  render() {
    // Function whose purpose of life to get the totalitems in the cart
    const getTotalItem = () =>{
      let totalItem = 0;
      this.props.cart.forEach(item => {
        totalItem += item.quantity;
      });
      return totalItem;
    }

    const getTotalPrice = (curren)  =>{
      let totalPrice = 0;
      this.props.cart.forEach(item => {
        let price =item.product.prices.find(
                  (e) => e.currency.label === curren
                ).amount
        totalPrice = totalPrice + item.quantity*price
        // totalPrice += item.price;
      });
      return parseFloat(totalPrice).toFixed(2);
    }
    return (
      <NavbarItem onClick={()=>{this.handleCartActive()}}>
        <NavbarItemIcon src="/assets/images/empty.png" alt="cart" />
                  {getTotalItem() ===0 ? "": <CartCount><span>{getTotalItem()}</span></CartCount>}
                  {this.state.isCartActive && <OverlayContainerWrapper ref={this.state.ref}> <OverlayCartContainer >
        <OverlayCartHeader>
                My Bag,   <span>{getTotalItem()} items</span>
        </OverlayCartHeader>
              <OverlayCartbody cartItem ={this.props.cart}/>
            <TotalContainer>
              <p>Total</p>
              <h6>{this.props.currencySymbol} {getTotalPrice(this.props.currencyState)}</h6>
            </TotalContainer>
            <ActionSection>
              <Link to={"/cart"}><ViewBagButton>VIEW BAG</ViewBagButton></Link>
              <CheckoutButton>CHECKOUT</CheckoutButton>
            </ActionSection>

        </OverlayCartContainer></OverlayContainerWrapper> }
      

      
      </NavbarItem>

    )
  }
}


const  mapStateToProps = (state) =>{
  return {
      currencyState:state.currency.currencyState,
      currencySymbol:state.currency.currencySymbol,
      cart:state.cart.cart.cartItems
  }
}
export default connect(mapStateToProps)(OverlayCart);

Solution

  • It works. It opens. It sets to true. But when you try to close you click outside + the icon. So 2 events occur. You are closing it with handleClickOutside and then opening it again with handleCartActive. The right solution would be to use backdrop. When the dialog is open, show the backdrop and add event listener to it: when clicked outside the dialog, close it. And after closing it remove the event listener.

    The quickest solution for you will be

    <NavbarItem onClick={this.state.isCartActive ? undefined : ()=>{this.handleCartActive()}}>