Skip to content
Advertisement

Submitting form with textarea in React

I have a textarea that I want to stringify to JSON on form submission. I will even settle for just having the function set the textarea value.

import React from 'react';

export default class ClinicalMain extends React.Component {
  constructor(props) {
    super(props);
  }

  state = {selectedOption: ''}

  // my function to update the textarea
  reactStringify() {
    let obj = {
      name: "bob",
      age: 4
    }

    console.log('in stringify');
    let value = JSON.stringify(obj);
  }

  componentDidMount() { }

  render() {
    return (
      <React.Fragment>
        <form>
          <button type="button" 
                  onClick={this.reactStringify} 
                  id="reactid"
          >React stringify</button>
          <textarea value={this.value} 
                    defaultValue="" 
                    rows="10" cols="80"
          ></textarea>
          <br />
        </form>
      </React.Fragment>
    )
  }
}

let value does not update. Do I need to use setState? this?

Advertisement

Answer

There are a number of issues in the code indicating a lack of familiarity with the excellent React tutorial. As with any library, it’s necessary to spend time reading the manual before diving in.

  1. State should not be modified directly. Use this.setState() to replace state. this.setState() doesn’t work instantly; it simply informs the React library that the state needs updating and React handles the update on its own when it sees fit.

    Beyond this, let value = ... is a purely local variable, not a class variable, so this.value would be undefined in render no matter what; in other words, your code doesn’t attempt to modify or access state in any way.

  2. Class functions that attempt to access this need to be bound. For example, onClick={this.reactStringify} passes a reference to the this.reactStringify function, but this will be undefined inside of this.reactStringify unless an arrow function is used (which implicitly binds this), or this is explicitly bound:

     this.handleChange = this.handleChange.bind(this);
    

    Explicit is considered to be better practice for class components than the arrow function approach because it only requires one call to bind when the component is constructed.

  3. React typically uses something called controlled components to listen to changes on a text field. This means that the element’s value tracks component state and acts as the single source of truth.

While I’m not exactly sure what you’re ultimately looking to accomplish, here’s a working example to get you moving again which demonstrates the above concepts.

class ClinicalMain extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: "", output: ""};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  
  handleChange({target: {value}}) {
    this.setState(() => ({value}));
  }

  handleSubmit(e) {
    e.preventDefault();
    this.setState(state => ({
      output: `you wrote: "${state.value}"`
    }));
  }

  render() {
    return (
      <React.Fragment>
        <form onSubmit={this.handleSubmit}>
          <textarea
            value={this.state.value}
            onChange={this.handleChange}
          ></textarea>
          <div>
            <input type="submit" value="Show output" />
          </div>
        </form>
        <div>{this.state.output}</div>
      </React.Fragment>
    );
  }
}

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<ClinicalMain name="World" />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

Here are relevant sections of the documentation which provide more detail:

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement