0

I am trying to set the state of features, which is an array, based on inputs into textarea. I am having no luck setting the state of features. When I press one key, that key becomes the next index value in the state. If I hit another key, that key becomes the next index value in the state. So if I manually set my initial state of features to features: ["First", "Second", "Third"],, the result will be features: ["First", "Second", "Third", "Firstf" , "Firstd"] if I hit f and then d

The relevant State

class CreateItem extends Component {
  state = {
    features: [""],
  };

This is how I am attempting to create textarea's based on the state

                <label htmlFor="features">
                  Features
                  {this.state.features.map((feature, i) => (
                    <div key={i}>
                      <textarea
                        key={i}
                        type="features"
                        placeholder={`${feature}`}
                        name={`features.${i}`}
                        value={this.state.features[`${i}`]}
                        onChange={this.handleFeatureArrayChange}
                        onKeyDown={this.keyPress}
                      />
                    </div>
                  ))}
                </label>

Here is the handleChange

  handleFeatureArrayChange = e => {
    const { name, type, value } = e.target;
    this.setState(prevState => ({
      [name]: [...prevState.features, value]
    }));
  };

This is how I am attempting to create new textarea's each time the user hits enter:

  keyPress = e => {
    if (e.keyCode == 13) {
      this.setState({
        features: this.state.features.concat("")
      });
    }
  };
realhat
  • 177
  • 1
  • 1
  • 9
  • No luck with what? You provided functionality for two distinct operations. Do neither work? Does one? Is there an error? What output are you actually receiving vs what you expect? – Brian Thompson Jan 23 '20 at 22:13
  • Good point. thank you. I am having no luck setting the state of features. When I press one key, that key becomes the next index value in the state. If I hit another key, that key becomes the next index value in the state. So if I manually set my initial state of features to `features: ["First", "Second", "Third"],`, the result will be `features: ["First", "Second", "Third", "Firstf" , "Firstd"]` if I hit f and then d – realhat Jan 23 '20 at 22:22

1 Answers1

0

The problem is you're just appending to state each time a key is pressed.

  handleFeatureArrayChange = e => {
    const { name, type, value } = e.target;
    this.setState(prevState => ({
      [name]: [...prevState.features, value] // this is effectively the same as .concat(value)
    }));
  };

You want to update the value at the current index. Try changing the name of the input to just be key and then mapping instead

  handleFeatureArrayChange = e => {
    const { name, type, value } = e.target;
    this.setState(prevState => ({
      features: prevState.features.map((feat, key) => {
        if (key == name) {
          return value
        } else
          return feat;
        }
      )
    }));
  };
Brian Thompson
  • 13,263
  • 4
  • 23
  • 43
  • You did it. Thank you so much Brian! I will study to your answer, because clearly I don't yet fully understand setState. Thanks again so much! – realhat Jan 24 '20 at 14:40
  • You're welcome. This issue is really more about how JavaScript arrays and the spread syntax work than setState itself. Its admittedly confusing because there's so many methods to use and its hard to remember which ones mutate and which ones return new. Or some even return deleted indexes or the new length of the array. I end up referencing the docs frequently to make sure I remember right. – Brian Thompson Jan 24 '20 at 14:45
  • [This question](https://stackoverflow.com/q/59867290/9381601) kind of addresses the same problem, with a few more detailed answers that might make things clearer. – Brian Thompson Jan 24 '20 at 14:47