1

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}/>
8
  • 3
    Your code seems to be incomplete, is it possible to edit and write the whole component ? jsfiddle or a codesandbox would be appreciated :) Commented May 22, 2020 at 9:43
  • my bad, i have added an example in the description. thanks Commented May 22, 2020 at 11:37
  • @yellowdev just a little check. At the beginning I've a dropdown and a button. Then I select a fruits. The effect is that now I've two fruits in the state. I click the button and than I've three dropdown. ------ At the beginning I've a dropdown and a button. The I select some fruit. The effect is that the state change, but I've a dropdown yet. If I click the buttons react render dropdowns for every single fruit selected. What's the correct behaviour? Commented May 22, 2020 at 15:10
  • @SorcererApprentice - When I first load the page by default in the state and UI there should be 1 fruit (eg Apple) If I click on the select and change the fruit to orange, there should still be 1 fruit in the state and UI but this time should be orange. When click ‘add fruit’ there should now be 2 fruits in the state and UI. 1 being the old orange and the the other being the new default state of Apple. Sorry if I’m not being clear. I’m new to developing Commented May 22, 2020 at 15:46
  • @yellowdev what about quantity? Commented May 22, 2020 at 15:51

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

thanks for your reply. i had already tried this before i raised the question and it does not work :(
@yellowdev when you click on an item of the select, what do you want to happens? .. with the code inside my answer, the behavoir is that a new select was added with a focus on the selected item of the existing one.
I want the state to update with the select values. I only want a new select if I click on the ‘add food’ button. With what you suggested a new select was being added when I select an option from the select. It was behaving weird and not what im after. There is a link to code sandbox in my description of what I have I currently have.
thanks alot mate. I got it working but your version seems much more better than mine. thanks :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.