React - Changing an Uncontrolled Input

React - changing an uncontrolled input

I believe my input is controlled since it has a value.

For an input to be controlled, its value must correspond to that of a state variable.

That condition is not initially met in your example because this.state.name is not initially set. Therefore, the input is initially uncontrolled. Once the onChange handler is triggered for the first time, this.state.name gets set. At that point, the above condition is satisfied and the input is considered to be controlled. This transition from uncontrolled to controlled produces the error seen above.

By initializing this.state.name in the constructor:

e.g.

this.state = { name: '' };

the input will be controlled from the start, fixing the issue. See React Controlled Components for more examples.

Unrelated to this error, you should only have one default export. Your code above has two.

(ReactJS) Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined ...

I've updated your component with this working example.

const { useEffect, useState } = React;

function Example({ user }) {

const [name, setName] = useState(user.name);

function handleChange(e) {
setName(e.target.value);
}

useEffect(() => console.log(name), [name]);

if(!user) return <div></div>;

return (
<form>
<fieldset>
<legend>Edit name</legend>
<input
id="name"
value={name}
onChange={handleChange}
/>
</fieldset>
</form>
)
};

const user = { name: 'Bob' };

ReactDOM.render(
<Example user={user} />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Warning: A component is changing an uncontrolled input to be controlled. Minimum working example

After adding value to TextField error disappears:

import React, { useState } from "react";
import MenuItem from "@mui/material/MenuItem";
import TextField from "@mui/material/TextField";

export default function Inputs() {
//const [gender, setGender] = useState("");
const [data, setData] = useState("");

return (
<TextField
select
value={data}
onChange={(e) => setData(e.target.value)}
>
<MenuItem key={"a"} value={"a"}>
a
</MenuItem>
</TextField>
);
}

Seems like TextField started in uncontrolled mode.

A component is changing an uncontrolled input of type text to be controlled error in ReactJS

The reason is, in state you defined:

this.state = { fields: {} }

fields as a blank object, so during the first rendering this.state.fields.name will be undefined, and the input field will get its value as:

value={undefined}

Because of that, the input field will become uncontrolled.

Once you enter any value in input, fields in state gets changed to:

this.state = { fields: {name: 'xyz'} }

And at that time the input field gets converted into a controlled component; that's why you are getting the error:

A component is changing an uncontrolled input of type text to be
controlled.

Possible Solutions:

1- Define the fields in state as:

this.state = { fields: {name: ''} }

2- Or define the value property by using Short-circuit evaluation like this:

value={this.state.fields.name || ''}   // (undefined || '') = ''

A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined

Issues

  1. 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.

  2. The other issue is not correctly shallow copying the existing nested contactUs state when new values arrive for other inputs. React's this.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>

Edit a-component-is-changing-a-controlled-input-to-be-uncontrolled-this-is-likely-ca

Warning: A component is changing an uncontrolled input to be controlled

If you set as undefined the value prop of your components they become uncontrolled. This is an example:

<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.id} // invoice.id is initially undefined
variant="outlined"
fullWidth
/>

Then, once you run the setInvoice() to define those values the components become controlled.
What you can do to make them always controlled is to set a proper initial value of the state like this:

const [invoice, setInvoice] = useState({ // Note that the initial value is an object and not an array
id: "",
issueDate: null,
netAmount: 0,
taxNumber: 0,
grossAmount: 0
});

Or alternatively you can do this to each of your components:

<TextField
className="mt-8 mb-16"
id="outlined-size-normal"
value={invoice.id || ""}
variant="outlined"
fullWidth
/>


Related Topics



Leave a reply



Submit