1

I’m trying to make a simple order system, when user selects QTY and click “Add to Order”, the information of the selected dish will be shown in the “Your Order” area (click “Refresh Order” to see). What I’m doing is to insert the dish information (from MenuEdit component) into a list (in CustomerOrder component).

My question is as following: I add “Moo Goo Guy Pan” QTY:1 to order, it will be inserted to the list, and then I add “Teriyaki Chicken” QTY:2, it will be inserted to the list, and I add “Moo Goo Guy Pan” again but QTY:3 to order, it will be inserted to the list. The uid is a timestamp when user click “Add to Order”. The list is working fine (I use lodash to deep copy), but when render all the item of the list is not good. I cannot think of a proper way to solve it. I’m willing to provide more information as you request. Thank you for your time and help.

I made a GIF to demonstrate the step and you can see the list changing in the console. link: https://github.com/Dungyichao/COVID19_Reporting_Web/blob/master/img/EggrollChenOrderSC.gif

User click the “Add to Order”, the first and the second step are doing good. enter image description here

The render steps of the Cart (Your Order), the first and the second step are doing good. enter image description here

The following is the list that is passed to the component for rendering. Note the qty is different, and this is the correct list which I want and already passed into CartList components. enter image description here

My Codes and Components structure is as follow enter image description here

Order.js

export default class CustomerOrder extends Component {

constructor(props) {

    super(props);

    this.firebase = props.firebase;
    this.sendinfo_toCart_handle = this.sendinfo_toCart_handle.bind(this);
    this.Cart_new_item_arrive = this.Cart_new_item_arrive.bind(this);
    this.remove_item = this.remove_item.bind(this);

    this.state = {
        Cart_data: [],
        Cart_new_item: '',
    }

    this.refresh_cart_handle = this.refresh_cart_handle.bind(this);
}

remove_item(e){
    console.log("Remove item uid: ", e);
}

refresh_cart_handle(){
    let {Cart_data} = this.state;
    console.log("Current Cart Data: ", Cart_data);
}

Cart_new_item_arrive(e){
    //console.log("Cart_new_item_arrive: ", e);
    this.setState({Cart_new_item: e}, () => {
        //after setstate
        this.sendinfo_toCart_handle();
    }); 
    
    
}

sendinfo_toCart_handle(){
    let {Cart_new_item, Cart_data} = this.state;
    let deepcopy_list = _.cloneDeep(Cart_data);
    deepcopy_list.push(Cart_new_item);
    this.setState({Cart_data: deepcopy_list});
}


render() {

    let {Cart_data} = this.state;

    return (
        <div style={order_style}>

            <div style={{
                
            }}>
                <h3>Menu</h3>
                <MenuEdit firebase={this.firebase} CartAdd={this.Cart_new_item_arrive} />

            </div>

            <div style={{
                
            }}>
                <h3>Your Order</h3>
                <Cart data_array={Cart_data} remove_item={this.remove_item} />   {/*remove_item={this.remove_item}*/}
                <Button onClick={this.refresh_cart_handle}>Refresh Order</Button>
            </div>

        </div>
    );

}

}

Cart.js

export default class Cart extends Component {

constructor(props) {

    super(props);

}

render() {
    return (
        <div>
            <div>
                <Scroll>
                    
                        <CartList data_array={this.props.data_array} remove_item={this.props.remove_item} />  {/*remove_item={this.props.remove_item}*/}
                    
                </Scroll>
            </div>
            <div>
                <div><Button>Refresh</Button></div>
                <div>
                    <Button>Cancel</Button> {'  '}
                    <Button>Place Order</Button>
                </div>
                
            </div>


        </div>
    );
}

}

CartList.js

export default class CartList extends Component {

constructor(props) {

    super(props);

}

render(){

    let display_data = this.props.data_array;
    let null_page = [];
    console.log("Data in CartList.js: ", display_data)

    if(display_data[0]){
        return(       
            display_data.map(
                (cart_item, idx) => {
                    //console.log("In Map", idx, ' Item: ', cart_item);
                    return(
                        <div>
                            <CartItem key={idx} u_key={idx + 1} 
                            Cart_item_info={cart_item} 
                            remove_item={this.props.remove_item} /> {/*remove_item={this.props.remove_item}*/}
                        </div>
                    );
                }
            )
        )
    }
    else{
        return(
            <div>
                <p>Add Your Favorite Dishes to Here</p>
            </div>
        );
    }

}

}

CartItem.js (which render each item in the list)

export default class CartItem extends Component {

constructor(props) {

    super(props);
    this.state = {
        show_toggle: true,
        cart_item_info: this.props.Cart_item_info,
        u_key: this.props.u_key,
        
    }
    //cart_item_info: this.props.Cart_item_info,
    this.remove_item_handle = this.remove_item_handle.bind(this);
}

remove_item_handle(){
    let {cart_item_info} = this.state;
    this.props.remove_item(cart_item_info.uid);
}

render() {
    let {cart_item_info, u_key} = this.state;
    //console.log("Return CartItem")
    return (
        <div key={u_key} >
            <Accordion>
                <Card>
                    <Accordion.Toggle as={Card.Header} eventKey="0">
                        <div style={item_style}>                                                          
                            <div style={{flex: '1'}}>{u_key}.</div>
                            <div style={{flex: '7'}}> {cart_item_info.dish_name}</div>
                            <div style={{flex: '2'}}>X {cart_item_info.qty}</div>
                            <div style={{flex: '2'}}>${cart_item_info.Tprice}</div>                                                       
                        </div>
                       
                    </Accordion.Toggle>
                    <Accordion.Collapse eventKey="0">
                        <Card.Body>
                            <Button onClick={this.remove_item_handle} >Remove</Button>
                        </Card.Body>
                    </Accordion.Collapse>
                </Card>                  
            </Accordion>
        </div>
    );
}

}

Dung-Yi
  • 45
  • 6

2 Answers2

1

Update your cartItem.js file. It should be functional component.

const CartItems = (props) => {

console.log(props.Cart_item_info);

return (
<div key={props.u_key} >
<Accordion>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="0">
<div>
<div style={{ flex: '1' }}>{props.u_key}.</div>
<div style={{ flex: '7' }}> {props.Cart_item_info.dish_name}</div>
<div style={{ flex: '2' }}>X {props.Cart_item_info.qty}</div>
<div style={{ flex: '2' }}>${props.Cart_item_info.Tprice}</div>
</div>

</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<div>No</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
);
}
deepak
  • 1,390
  • 1
  • 8
  • 12
  • What do you mean update the count? I thought react would re-render whenever anything in this.state got changed?? – Dung-Yi Sep 16 '20 at 04:28
  • I would take whatever user add, the uid (timestamp is always different) even the dish name, qty are the same – Dung-Yi Sep 16 '20 at 04:37
  • Product id or article id should be same even if you are adding at different timestamp. Do check with that id. – deepak Sep 16 '20 at 05:33
  • React re-render whenever state change and it is doing the same for you but somehow you are adding new product rather than updating the existing one. – deepak Sep 16 '20 at 05:35
  • If there is no unique code with each product kindly add the same with each product and resolve this issue. – deepak Sep 16 '20 at 05:36
  • The Cart_data_array contains the correct items. Render has problem at step 3 (which render the first and third to be identical) and at step 4 (which render the second and the fourth to be identical). My Cart_data_array contains non-duplicate item though. – Dung-Yi Sep 16 '20 at 05:39
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/221549/discussion-between-deepak-and-dung-yi). – deepak Sep 16 '20 at 05:43
0

I finally find the root cause of the problem which I didn't reveal it in the question because I don't even think that would cause a problem

enter image description here

The problem is from the MenuItem component (Menu item which user can click Add to Order). The correct way is to clear all data (which is going to insert to list in Order.js) hold in the state of the MenuItem component whenever it has already already inserted. By doing so you can prevent any original data being sent again.

Also in the chat room with Deepak, he suggest some following tips:

  1. When you want to just show something and no state management than prefer functional component.
  2. key help react to identity the item change in the list.
Dung-Yi
  • 45
  • 6