A component is changing an uncontrolled input to be controlled

avatar
Borislav Hadzhiev

Last updated: Apr 6, 2024
3 min

banner

# A component is changing an uncontrolled input to be controlled

The warning "A component is changing an uncontrolled input to be controlled" occurs when an input value is initialized to undefined but is later changed to a different value.

To fix the warning, initialize the input value to an empty string, e.g. value={message || ''}.

component changing uncontrolled input

Here is an example of how the error occurs.

App.js
import {useState} from 'react'; const App = () => { // ๐Ÿ‘‡๏ธ didn't provide an initial value for `message` const [message, setMessage] = useState(); const handleChange = event => { setMessage(event.target.value); }; // โ›”๏ธ Warning: 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. return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message} /> </div> ); }; export default App;
The code for this article is available on GitHub

The issue is that the message state variable is initially set to undefined because we didn't pass an initial value for it to the useState hook.

# Provide a fallback value if undefined

One way to solve the error is to provide a fallback if the input value is undefined.

App.js
import {useState} from 'react'; const App = () => { const [message, setMessage] = useState(); const handleChange = event => { setMessage(event.target.value); console.log(event.target.value); }; // ๐Ÿ‘‡๏ธ value={message || ''} return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message || ''} /> </div> ); }; export default App;

provide fallback value if undefined

The code for this article is available on GitHub

We used the logical OR (||) operator, which returns the value to the right if the value to the left is falsy (e.g. undefined).

If the message variable stores an undefined value, we return an empty string as a fallback.

# Pass an initial value for the state variable to the useState hook

An alternative solution is to pass an initial value for the state variable to the useState hook.

App.js
import {useState} from 'react'; const App = () => { // ๐Ÿ‘‡๏ธ Pass an initial value to the useState hook const [message, setMessage] = useState(''); const handleChange = event => { setMessage(event.target.value); console.log(event.target.value); }; return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message} /> </div> ); }; export default App;

pass initial value for state variable to usestate

The code for this article is available on GitHub

Passing an initial value to the useState hook gets rid of the warning because now the message variable doesn't change from undefined to having a value.

The warning is caused because when the message variable is initialized without a value, it is set to undefined.

Passing a prop like value={undefined} is the same as not passing the value prop at all.

Once the user starts typing in the input, the value prop is now passed to the input field and the input changes from uncontrolled to controlled which is not allowed.

# Using defaultValue prop for uncontrolled components

Note that if you use an uncontrolled input field, you should use the defaultValue prop instead of value.

App.js
import {useRef} from 'react'; const App = () => { const inputRef = useRef(null); function handleClick() { console.log(inputRef.current.value); } return ( <div> <input ref={inputRef} type="text" id="message" name="message" defaultValue="Initial value" /> <button onClick={handleClick}>Log message</button> </div> ); }; export default App;

uncontrolled input default value

The code for this article is available on GitHub

The example above uses an uncontrolled input. Notice that the input field doesn't have an onChange prop or value set.

You can pass an initial value to an uncontrolled input with the defaultValue prop. However, this is not necessary and you can omit the prop if you don't want to set an initial value.

When using uncontrolled input fields, we access the input using a ref.

Every time the user clicks on the button in the example, the value of the uncontrolled input gets logged.

You shouldn't set the value prop on an uncontrolled input (an input field that doesn't have an onChange handler) because that would make the input field immutable and you wouldn't be able to type in it.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev