简体   繁体   中英

update state multiple dropdown REACT

I have a button which adds a dropdown select based on the number of array item set in my state.

I am able to add a new dropdown, however i am having difficulties updating the state with their value for each dropdown. Every time i select the dropdown and change the option, the state reverts back to only have 1 item in the array.

any ideas of on how i am able to set the state with their current values for each dropdown that i have?

Codesandbox example

    state = {
            food: [
               {name: 'Apple', quantity: 1}
            ],
        };

    const addFood = this.state.food.map((item, idx) => {

    return 
         <Dropdown type="food"
              className="dropdown-food"
              label='food'
              key={idx}
              value={this.state.food[idx].name}
              change={(event) => this.setState({ food: [{ name: event.target.value, quantity: this.state.food[idx].quantity }] })}
         />

    })

    <Button styleName="add" label="Add Food" clicked={this.addAdditionalFood}/>

I fixed your problem. Now the code works as expected: 1. When a click occurs on the button, a new dropdown and a new element in the state are added. 2. When the value on the dropdown changes, its state change accordingly.

To fix the problem I changed code only in App.js file. Here the full code:

import React, { Component } from "react";
import Dropdown from "./Dropdown";
import Button from "./Button";

class App extends Component {
  state = {
    food: [{
        name: "Apple",
        quantity: 1
      }]
  };

  addAdditionalFood = () => {
    const newState = {...this.state, 
      food : [...this.state.food,{
       name: "Apple",
       quantity: 1
      } ]};
    this.setState(newState);
  };

  selectFood = (event, index) => {
    const newState = {...this.state, 
      food : [
          ...this.state.food.slice(0, index),
          {
            ...this.state.food[index],
            name: event.target.value,
          },
          ...this.state.food.slice(index + 1)
            ]};
    this.setState(newState);
  }


  render() {
    const addFood = this.state.food.map((item, idx) => {
      return (
        <Dropdown
          type="food"
          label="food"
          key={idx}
          value={this.state.food[idx].name}
          change={(event) => this.selectFood(event, idx)}
        />
      );
    });

    return (
      <div className="App">
        {addFood}
        <Button label="Add Food" clicked={this.addAdditionalFood} />
      </div>
    );
  }
}

export default App;

Here the code to add an additional state for a new dropdown:

 addAdditionalFood = () => {
    const newState = {...this.state, 
      food : [...this.state.food,{
       name: "Apple",
       quantity: 1
      } ]};
    this.setState(newState);
  };

To ensure the immutability of the state, it is good practice not to make changes directly to the state, but manipulating the data of shallow copies. In this piece of code, I tell to do a shallow copy of the state, a shallow copy of food and, finally, to add to the food shallow copy a new value. At the end, I set the new state.

Here the code to change the state of a dropdown:

selectFood = (event, index) => {
    const newState = {...this.state, 
      food : [
          ...this.state.food.slice(0, index),
          {
            ...this.state.food[index],
            name: event.target.value,
          },
          ...this.state.food.slice(index + 1)
            ]};
    this.setState(newState);
  }

This function takes as input the event and the index of the dropdown; the event contains the new value assumed by the dropdown - this value must be entered in the state. In this piece of code, I tell to do a shallow copy of the state, a rearranged shallow copy of food. The shallow copy is so composed: it's equal to original before and after the index position and different at the index position. The element at the index position is a shallow copy of the original, but it differs from the original by the name. At the end, I set the new state.

Here the code rendering the dropdown:

<Dropdown
          type="food"
          label="food"
          key={idx}
          value={this.state.food[idx].name}
          change={(event) => this.selectFood(event, idx)}
        />

Now it doesn't contain logic, but only a lambda. Don't define logic inside jsx, but use lambda at class level instead.

If change the quantity for the fruits, I suggest to wrap dropdown and input box together and pass to this new component two functions: selectFood and selectQuantity.

note: I apologize from my previous answers and them bugs. Now, the code works and apply correctly immutability.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM