0
votes

I'm new to React. I have two sibling component Top Bar and Home (according to the redux doc, redux can use to share state between the components ). and actions fil which use to handle the actions. and reducer, use to manage the logic. my issue is, one component dispatch an action the other component receive the update, but not render. but the component, which invokes the dispatch action, it works. in my console show no error. I use the immutable pattern indie the reducer to handle the logic.

the react doc noted that stay away from following functions componentWillReceiveProps() & componentWillUpdate()

Tob Bar.js

class TopBar extends React.Component {



    constructor(props) {
        super(props);

    }

    render() {

        return (
            <div>
              <IconButton color="inherit">
                 <Badge badgeContent={this.props.cart.length} >
                       <ShoppingCart />
                   </Badge>
                </IconButton>

            </div>
        )
    }
}

const mapStateToProps =(state)=>{
   // here I get the update but not render
    return{
        'cart':state.ItemReducer.cart
    }
}

export default connect(mapStateToProps)(withStyles(Styles)(TopBar))

Home.js

layout component as the parent component

       class Home extends Component {

        addToCart(event,item){
            this.props.addToCart(item);
        }

         render() {

            return (
              <Layout>
                <IconButton className={classes.icon} onClick={(e)=>{addtoCart(e,tile)}}> <ShoppingCart /></IconButton>
             </Layout>
            )
        }
    }

const mapStateToProps =(state)=>{

    return{
        'items':state.ItemReducer.items,
        'cart':state.ItemReducer.cart
    }
}

export default connect(mapStateToProps,actions)(withStyles(Styles)(Home));

Layout.js

class Layout extends Component {

    render() {
        return (
            <div>
                <TopBar {...this.props} />
                {this.props.children}
            </div>
        )
    }
}

export default Layout;

Action.js

  export function addToCart(item){
      return (dispatch)=>{
        dispatch({type:'ADD_CART',item:item})
      }
  }

Reducer.js

let initState = {
    'items': [],
    'cart':[]
};

const ItemReducer = (state = initState, action) => {
    switch (action.type) {
        case 'ADD_CART':

            let cart = {...state}.cart;
            for(var i in cart){
                if(cart[i].product_id === action.item.product_id){
                    return{
                        ...state
                    }
                }
            }

             cart.push(action.item)

            return{
                ...state,
                'cart':cart
            }
   }
}
1
how are you determining that its not rendering? Have you tried putting a console log in the body of your render function? - azium
the other component receive the update, but not render - what does this mean? How did you determine this? - Estus Flask
let cart = {...state}.cart; is completely unnecessary! - Matt
@azium I put console log under mapStateToProps function and render function (in Tob Bar.js) when I click the icon button in Home js, console log is the trigger (under mapStateToProps function). but won't trigger under render function. - Maru
@estus I put the console logs under mapToState function and render function - Maru

1 Answers

0
votes

I don't think you can push to the 'cart' object directly since this mutates the state and won't trigger an update.

You need to first (deep) clone the cart object (I've used lodash here):

case 'ADD_CART':

  let cartClone = _.cloneDeep(this.state.cart);
  for(var i in cartClone){
      if(cartClone[i].product_id === action.item.product_id){
          return state;
      }
  }

  cartClone.push(action.item)

  return {
      ...state,
      cart: cartClone
  }