A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined
Issues
-
React uses Synthetic Events that are quickly nullified and returned back to the event pool. By the time the state update is processed the event object has been nullified and your state values set to undefined. This causes the controlled to uncontrolled input warning.
-
The other issue is not correctly shallow copying the existing nested
contactUs
state when new values arrive for other inputs. React'sthis.setState
only merges root level state, all deeper state should be manually merged.
Solution
Save the input value before enqueueing the state update. Use a functional state update to access the previous state.
handleFirstNameChange = (event) => {
const { value } = event.target;
this.setState(prevState => ({
contactUs: {
...prevState.contactUs, // <-- copy other nested state
name: value,
},
}));
};
Suggestion
To make your code a bit more DRY you can define a single onChange
handler to handle all the inputs.
handleChange = (event) => {
const { id, value } = event.target;
this.setState((prevState) => ({
contactUs: {
...prevState.contactUs,
[id]: value
}
}));
};
The inputs. Ensure all the id
attributes match their react state counterpart. Use the same handler for each.
<div className="form-element">
<label>Name:</label>
<input
type="text"
id="name"
value={this.state.contactUs.name}
onChange={this.handleChange}
/>
</div>
<div className="form-element">
<label>Email:</label>
<input
type="email"
id="emailAddress"
value={this.state.contactUs.emailAddress}
onChange={this.handleChange}
/>
</div>
<div className="form-element">
<label>Telephone:</label>
<input
type="text"
id="telephone"
value={this.state.contactUs.telephone}
onChange={this.handleChange}
/>
</div>
Related videos on Youtube
wiki
Updated on June 04, 2022Comments
-
wiki 7 months
This is my ContactUs component
import React, { Component } from "react"; import { Button } from "react-bootstrap"; class ContactUs extends Component { constructor(props) { super(props); this.state = { contactUs: { telephone: "", name: "", emailAddress: "", }, }; } render() { return ( <div> <h2>Contact Us</h2> <div className="form-element"> <label>Name:</label> <input type="text" id="name" value={this.state.contactUs.name} onChange={this.handleFirstNameChange} /> </div> <div className="form-element"> <label>Email:</label> <input type="email" id="email" value={this.state.contactUs.emailAddress} onChange={this.handleEmailChange} /> </div> <div className="form-element"> <label>Telephone:</label> <input type="text" id="telephone" value={this.state.contactUs.telephone} onChange={this.handletelephoneChange} /> </div> <Button onClick={this.sendEmail}>Send Email</Button> </div> ); } handleFirstNameChange = (event) => { this.setState({ contactUs: { name: event.target.value } }); }; handletelephoneChange = (event) => { this.setState({ contactUs: { telephone: event.target.value } }); }; handleEmailChange = (event) => { this.setState({ contactUs: { emailAddress: event.target.value } }); }; sendEmail = () => { console.log("Name is " + this.state.contactUs.name); console.log("Email address is " + this.state.contactUs.emailAddress); console.log("Telephone is " + this.state.contactUs.telephone); }; } export default ContactUs;
These are questions related to above component.
- When I add something to one of three elements in the component, I received following error. How can I get rid of the error?
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
- After I filled Name, telephone and email and press the button, I received following output.
Name is undefined
Email address is undefined
Telephone is Test TelephoneWhy the output does not contain the values for Name and email address?
Thanks in advance.
-
Rohit Khanna almost 2 yearsWriting this
this.setState({ contactUs: { telephone: event.target.value } })
overrides existingcontactUs
state completely ascontactUs
is anobject
, Replace this bythis.setState({ contactUs: {...this.state.contactUs, telephone: event.target.value } })
so that you donot get undefined in final values.