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.
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, sothis.value
would be undefined inrender
no matter what; in other words, your code doesn’t attempt to modify or accessstate
in any way.Class functions that attempt to access
this
need to be bound. For example,onClick={this.reactStringify}
passes a reference to thethis.reactStringify
function, butthis
will be undefined inside ofthis.reactStringify
unless an arrow function is used (which implicitly bindsthis
), orthis
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.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: