Guerrilla
Guerrilla

Reputation: 14926

Textarea not updating when state updates

I am trying to get functionality where a drop down option can be selected and a text area matches it's text to that option.

So if I select option 1 then type, select option 2 it is clear so I type something else. Now if I switch between option 1 & 2 I can see the text I typed for each option.

I have bound the value of the textarea to an object property data[selected] but when this state value updates the text area does not update. What did I do wrong?

Here is my code:

(code sandbox: https://codesandbox.io/s/hardcore-fog-3pibo?file=/src/App.jsx)

import React, { useState, useEffect } from "react";
import "./styles.css";

export default function App() {
  const parentData = ["one", "two", "three"];

  const [selected, setSelected] = useState("two");
  const [data, setData] = useState(
    parentData.reduce((a, b) => ((a[b] = ""), a), {})
  );

  function handleSelect(event) {
    setSelected(event.target.value);
  }

  function handleTextChange(event) {
    let val = event.target.value;
    setData((prev) => {
      prev[selected] = val;
      return prev;
    });

    console.log(data[selected]);
    console.log(selected);
    console.log(val);
  }

  return (
    <div className="App">
      <h1>Selected is: {selected}</h1>
      <select value={selected} onChange={handleSelect} name="" id="">
        {parentData.map((val, i) => {
          return (
            <option key={i} value={val}>
              {val}
            </option>
          );
        })}
      </select>
      <br /> <br />
      <textarea
        onChange={handleTextChange}
        value={data[selected]}
        name="data"
        id=""
        cols="30"
        rows="10"
      ></textarea>
      {console.log("parent render")}
    </div>
  );
}

Upvotes: 1

Views: 384

Answers (3)

joashe
joashe

Reputation: 3

Yash Joshi's answer was perfect, except my solution was in class form. So that my

<textarea value={this.state.myText} onChange={this.changeMyText} />

Would not be changed by

someOtherFunction(){
     this.setState({
          myText: this.state.myText + "abcde"
     });
}

And instead the solution was to change this to

someOtherFunction(){
     let newtext = this.state.myText + "abcde";
     this.setState({
          myText: newtext;
     });
}

But surreal enough is that this solution isn't required for just regular <input/>s

Upvotes: 0

Yaiza del R&#237;o
Yaiza del R&#237;o

Reputation: 106

You need to use the spread operator, this way, you will add the new value, and not mutate the state.

function handleTextChange(event) {
    let val = event.target.value;
    setData(data => ...data, val)

}

Upvotes: 0

Yash Joshi
Yash Joshi

Reputation: 2784

In handleTextChange you are mutating the object. Try doing the below:

setData((prev) => {
      return {
        ...prev,
        [selected]: val
      };
    });

Upvotes: 2

Related Questions