A component is changing an uncontrolled input to be controlled.

Posted on

React provides a warning message when a component changes an uncontrolled input to a controlled one. This typically happens when using the <input> element.

A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.

uncontrolled controlled input

Below is an example of how the error occurs. Try to type something in the input and inspect the devtools to see the message. (CodeSandbox)

export default function App() {
const [name, setName] = useState(); // use `undefined` value

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

return <input id="name" value={name} onChange={handleChange} />;
}

The primary cause is the App attempting to change name from undefined to a defined value. Before discussing solutions, let's first understand the differences between uncontrolled vs controlled inputs.

Uncontrolled input

Uncontrolled inputs are those where React doesn't control or update the value. Examples include:

<input />;
<input type="checkbox" />;

Interestingly, React provides defaultValue and defaultChecked props to set the initial value as seen below. They also don't make input as controlled input.

<input defaultValue="John Doe" />;
<input type="checkbox" defaultChecked />;

Converting uncontrolled input to controlled

To create a controlled input, pass the value prop for text inputs or checked prop for checkbox or radio inputs. Controlled inputs are typically used with useState, allowing React to manage the value.

export default function App() {
const [name, setName] = useState('');

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

return (
<div>
<input onChange={handleChange} id="name" value={name} />;
{name && <p>My name is {name} </p>}
</div>
)
}

With this understanding. Let's jump into the solution which turn out to be simple 😄.

Solution: provide fallback value if undefined

In our previous code example that cause the error, instead of undefined, we could give empty string as initial value.

const [name, setName] = useState('');

Alternatively, we could also provide the fallback value in the value prop

return <input id="name" value={name || ''} onChange={handleChange} />;