Got all button updated in reactjs onclick event

Viewed 616

A single click on a button updates all the buttons but I want to change the state of that particular clicked button. Please check the image links below and the code.

import React from 'react';
import './MenuCard.css';

class MenuCard extends React.Component {

constructor(props) {
    super(props);
    this.state = {
        showButton: false,
        hideButton: true,
        aValue: 1,
        breads: [],
        category: [],
        ids: 1,
        btnVal: 'Add'

    };
}

onKeyCheck = (e) => {
    this.state.breads.map(filt => {
        if (filt.id === e.target.id) {
            console.log(e.target.id + ' and ' + filt.id)
            return (this.setState({showButton: !this.state.showButton, hideButton: !this.state.hideButton}));
        }
    })
}

onShowButton = () => {
    this.setState({showButton: !this.state.showButton, hideButton: !this.state.hideButton})
}
onValueIncrease = () => {
    this.setState({aValue: this.state.aValue + 1});
}

onValueDecrease = () => {
    this.setState({aValue: this.state.aValue - 1});
}

componentDidMount() {
    fetch('http://localhost:3000/menu/food_category', {
        method: 'get',
        headers: {'content-type': 'application/json'}
    })
        .then(response => response.json())
        .then(menudata => {
            this.setState({category: menudata.menu_type})
            console.log(this.state.category)
        })

    fetch('http://localhost:3000/menu', {
        method: 'get',
        headers: {'content-type': 'application/json'}
    })
        .then(response => response.json())
        .then(menudata => {
            this.setState({breads: menudata  })
        })
}


render() {

    return (
        <div>
            {this.state.category.map(types => {
                return (<div>
                    <div className="menu-head">{types}</div>
                    < div className="container-menu">
                        {this.state.breads.map((d, id)=> {
                            if (d.category === types) {
                                return (
                                    <div>
                                        <div className="content" key={id} id={d.id}>
                                            <div className="items"> {d.item_name}</div>
                                            <div className="prices"> {d.price} Rs.</div>
                                            {this.state.showButton ?
                                                <div>
                                                    <button
                                                        className="grp-btn-minus"
                                                        onClick={this.state.aValue <= 1 ?
                                                            () => this.onShowButton() :
                                                            () => this.onValueDecrease()}>-
                                                    </button>
                                                    <input className="grp-btn-text" type="text"
                                                           value={this.state.aValue} readOnly/>
                                                    <button id={d.id}
                                                            className="grp-btn-plus"
                                                            onClick={() => this.onValueIncrease()}>+
                                                    </button>
                                                </div> :
                                                <button id={d.id} key={id}
                                                        onClick={ this.onKeyCheck}
                                                        className="add-menu-btn">
                                                    add
                                                </button>
                                            }
                                        </div>
                                    </div>
                                )
                            }
                        })}
                    </div>
                </div>)
            })}
        </div>
    )
}
}

export default MenuCard;

This is the first image of multiple rendering of component Add buttons

Here is the problem that all buttons get updated on single click

2 Answers

You're using an array of items but refering to a single, shared value in handlers. De facto you're using a few shared values: showButton, hideButton, aValue), 2/3 unnecessary ;)

First - aValue for each item should be stored in a structure - array or object. It could be an order = {} - object with id-keyed properties with amounts as values like this:

order = {
  'masala_id': 1,
  'kebab_id' : 2
}

Event handler (for 'add') should check if id for choosen product already exist in order object (as property name) and update amount (+/-) or create new one with 1 value (and remove property when decreased amount = 0).

In practice order should also contain a price - it seams like duplicating data but it will be much easier to count total order value.

order = {
  'masala_id': {
      'amount': 1,
      'price': 20,
    },
  'kebab_id' : {
      'amount': 2,
      'price': 180,
    }
}

Item doesn't need to be a component but it's much easier to maintain it, keep it readable etc.

This way we can simply pass already ordered amount and conditionally render buttons:

<Product id={d.id}
  name={d.item_name}
  price={d.price}
  amount={order[d.id] ? order[d.id].amount : 0 }
  amountHandler={this.changeAmountHandler}
/>

Product should be slightly improved and simplified (f.e. key is needed on top div):

class Product extends React.Component {
  render () {
    const (id, name, price, amount, amountHandler} = this.props;
    const showIncrease = !!amount; // boolean, it also means "don't show add button"
    return (
      <div key={id} >
        <div className="content">
          <div className="items">{name}</div>
          <div className="prices">{price} Rs.</div>
          {showIncrease ?
            <div>
              <button
                className="grp-btn-minus"
                onClick={(e) => { amountHandler(e, id, -1) }}
              >-</button>
              <input className="grp-btn-text" type="text"
                value={amount}
                readOnly/>
              <button 
                className="grp-btn-plus"
                onClick={(e) => { amountHandler(e, id, 1) }}
              >+</button>
            </div> :
            <button 
              onClick={(e) => { amountHandler(e, id, 1) }}
              className="add-menu-btn"
            >add</button>
          }
        </div>
      </div>
    )}}

This way you can handle all events in one handler, keep entire order state in main component... in case of performance problems just use PureComponent.

It looks like all the buttons are sharing the same state. You could try breaking the button up into its own component, and then move the state that button needs into there. That way when you click a button the state of that one particular button is updated, and not the state of the parent component that contains all the buttons.

Related