Hman
Hman

Reputation: 393

How to Update single value from array of Objects and then Update State

I have an array of objects

const array = [
  { itemId: "optionOne", name: "Option One", quantity: 10 },
  { itemId: "optionTwo", name: "Option Two", quantity: 20 },
  { itemId: "optionThree", name: "Option Three", quantity: 30 }
];

I need to update just the quantities using input box and then update state. end with something like this enter image description here

whats the best way to do this.

PLEASE find attached code example ready to modify handleChange() function CodeSandbox

Upvotes: 1

Views: 233

Answers (2)

mhodges
mhodges

Reputation: 11126

If you want to store and update state, you need to add your data to the component state. This can be done in the constructor, and then modified using setState() in any of your component methods (i.e. if you are getting the data from an API, or modifying with your change handler). The component would look something like this:

constructor(props) {
  super(props);
  // set initial state, set to { array: [] } if getting data from API
  this.state = {
    array: [
      { itemId: "optionOne", name: "Option One", quantity: 10 },
      { itemId: "optionTwo", name: "Option Two", quantity: 20 },
      { itemId: "optionThree", name: "Option Three", quantity: 30 }
    ]
  };
}
handleChange = (itemIndex, itemValue) => {
  console.log(itemIndex, itemValue);
  // set state to changed values
  this.setState({
    array: this.state.array.map((item, index) => {
      // update item quantity (or clone & mutate if you need to maintain immutability)
      if (index === itemIndex) { item.quantity = +itemValue };
      return item;
    })
  });
};
render() {
  return (
    <div>
      {this.state.array.map((item, key) => {
        return (
          <FormGroup controlId="siteVisit">
            <Row>
              <Col xs={12} md={4}>
                <h3>{item.name}</h3>
              </Col>
              <Col xs={12} md={8}>
                <FormControl
                  type="text"
                  key={item.itemId}
                  onChange={item => {
                    this.handleChange(key, item.target.value);
                  }}
                />
                <span>{item.quantity}</span>
              </Col>
            </Row>
          </FormGroup>
        );
      })}
    </div>
  );
}

Edit

While the above solution is relatively simple, depending on your app structure, it might make more sense to use an "event emitter"-like function that you pass through that gets called instead. That way, there is no need to store or update state inside your child component - it becomes stateless and purely presentational. All of the data mutations/updates will happen on the parent and simply be passed down to the child for display. The main reason for wanting to do this is if the data changes and new data gets sent down from the parent. If you're not listening/reacting to changes in the child props, those changes will never trigger updates to your child component unless you explicitly listen for the changes, in which case, you're duplicating code. Anyway, might be overkill for this simple example, but it's something worth thinking about.

Upvotes: 2

Chris B.
Chris B.

Reputation: 5763

As mentioned in the comments, you should be storing your data in the state if you want to edit it. You have a decent start feeding in the index and value to the change function. Then you need to duplicate the array to prevent direct state mutation, alter the value accordingly and use setState to register the changes with React.

Fork here.

Upvotes: 2

Related Questions