Amit Erandole
Amit Erandole

Reputation: 12271

Why is my react component not updating?

I have a simple Cart component and I want to show either a "Your cart is empty" message when there are no items in it.

import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as CartActions from '../actions/cart'
import Shelf from './Shelf'
import EmptyCart from './EmptyCart'

/*
This is a container component
*/
class Cart extends Component {

  constructor(props) {
    super(props)
    this.state = {
      itemQuantity: props.cart.length
    }
  }

  render() {
    const CartItems = this.props.cart.map(
      (item, idx) =><li key={idx}>{item.name} - ${item.price}</li>
    )

    const isCartEmpty = () => this.state.itemQuantity === 0

    console.log("is cart empty? ", isCartEmpty(), "cart item quantity ", this.state.itemQuantity)

    return(
      <div className="Cart">
        <Shelf addItem={this.props.action.addToCart} />
        <h2>Cart Items</h2>
        <ol>
        { isCartEmpty() ? <EmptyCart/> : {CartItems} }
        </ol>
      </div>
    )
  }
}

function mapStateToProps(state, prop) {
  return {
    cart: state.cart
  }
}

function mapDispatchToProps(dispatch) {
  return {
     action: bindActionCreators(CartActions, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Cart)

My Shelf component looks like this:

import React, { Component } from 'react';

class Shelf extends Component {
  constructor(props) {
    super(props)

    this.addItemToCart = this.addItemToCart.bind(this)

    this.state = {
      shelfItems: [
        { "name": 'shampoo', "price": 23 },
        { "name": 'chocolate', "price": 15 },
        { "name": 'yogurt', "price": 10 }
      ]
    }
  }

  addItemToCart(item){
    this.props.addItem(item)
  }

  render() {
    const shelfItems = this.state.shelfItems.map((item, idx) => {
      return <li key={idx}><button onClick={()=>this.addItemToCart(item)}>[+]</button>{item.name} - ${item.price}</li>
    })
    return(
      <div>
        <h2>Shelf</h2>
        <ul>
          {shelfItems}
        </ul>
      </div>
    )
  }
}
export default Shelf

Cart Reducer:

export default(state = [], payload) => {
  switch (payload.type) {
    case 'add':
      return [...state, payload.item]
    default:
      return state
  }
}

addToCart action:

export const addToCart = (item) => {
  return {
    type: 'add',
    item
  }
}

The empty message shows up but the list does not update when I add items. What am I doing wrong? The code works just fine if I remove the conditionals and just render CartItems

Upvotes: 0

Views: 1323

Answers (1)

Max Alekseenko
Max Alekseenko

Reputation: 346

It's because you set only initial state. When you add item you don't set a new state. If you use redux there is no local state needed.

Try this:

class Cart extends Component {

  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    const CartItems = this.props.cart.map(
      (item, idx) =><li key={idx}>{item.name} - ${item.price}</li>
    )

    const isCartEmpty = CartItems.length === 0

    return(
      <div className="Cart">
        <Shelf addItem={this.props.action.addToCart} />
        <h2>Cart Items</h2>
        <ol>
         {isCartEmpty ? <li>Your Cart is Empty</li> : CartItems}
        </ol>
      </div>
    )
  }
}

Upvotes: 1

Related Questions