Last updated: Apr 6, 2024
Reading time·3 min
To solve the issue of being unable to type in an input field in React, make
sure to use the defaultValue
prop instead of value
for uncontrolled input
fields.
Alternatively, set an onChange
prop on the field and handle the change
event.
Here is an example of how the issue occurs.
const App = () => { return ( <div> <input type="text" value="initial value" /> </div> ); }; export default App;
The problem is that the input
field has a value
prop set, but it doesn't
have an onChange
prop that handles changes to the input's value.
onChange
prop to resolve the issueThe easiest way to get around this is to use the onChange
prop to handle the
change event on the input
field.
import {useState} from 'react'; const App = () => { const [message, setMessage] = useState('Initial value'); // 👇️ Called every time input's value changes const handleChange = event => { setMessage(event.target.value); }; console.log(message); return ( <div> <input id="message" name="message" type="text" onChange={handleChange} value={message} /> </div> ); }; export default App;
We used the onChange
prop to handle the change event on the input field. The
handleChange
function is invoked every time the value of the field changes.
Notice that we store the value of the input
in the state.
The useState hook can be passed an initial state value.
useState
hook, e.g. const [message, setMessage] = useState('')
.Now every time the user types into the input field, the handleChange
function
gets called and sets a new value for the message
variable, which rerenders the
input
field and shows the current value.
An alternative way to handle the issue where we can't type in an input is to use an uncontrolled input field.
import {useRef} from 'react'; const App = () => { const ref = useRef(null); const handleClick = () => { // 👇️ ref.current is a reference to the input field console.log(ref.current.value); }; return ( <div> <input ref={ref} id="message" name="message" defaultValue="Initial value" type="text" /> <button onClick={handleClick}>Log input value</button> </div> ); }; export default App;
The useRef() hook can be passed an
initial value as an argument. The hook returns a mutable ref object whose
.current
property is initialized to the passed argument.
current
property on the ref object to get access to the input
element on which we set the ref
prop.When we pass a ref prop to an element, e.g. <input ref={myRef} />
, React sets
the .current
property of the ref object to the corresponding DOM node.
useRef
hook creates a plain JavaScript object but gives you the same ref object on every render. In other words, it's pretty much a memoized object value with a .current
property.It should be noted that when you change the value of the current
property of
the ref, no re-renders are caused.
Now every time the user clicks on the button, the value of the input field is logged. This pattern is called uncontrolled components.
Notice that we used the defaultValue
prop instead of value
. The
defaultValue
prop allows us to specify an initial value for the input field.
If you set the value
prop on an input field, you are required to also set
the onChange
prop and handle the change event, otherwise, you can't type in
the input field.