Reputation: 365
The UserForm which is controlled by another controller complains on console as
"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. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components input span li ul..."**
This is the component code:
export default({user}) => {
if(!user) {
return <div></div>
} else {
const [name,setName] = useState(user.name|| "")
useEffect(() => {
setName(user.name);
}, [user])
return <form>
<fieldset>
<legend> Edit {user.name }</legend>
<p>
<label htmlFor={"name"}> Name </label>
<input id="name" value={name || ""} onChange={e => setName(e.target.value)} />
</p>
</fieldset>
</form>
}
}
I tried all fixes suggested on other stackoverflow answers but still gives warning.
Is there something I migth missing?
Upvotes: 7
Views: 37894
Reputation: 5049
If you have your initial value undefined
You can use the or notation to fallback to an initial empty string.
const [someValue, setValue] = useState<string | undefined>();
...
<input
value={someValue ?? ''}
onChange={e => setValue(e.target.value)}
/>
Upvotes: 0
Reputation: 635
This problem mainly occurs when you have an undefined value for an attribute, now it can be checked
for <input />
field or type
or even value
attribute.
Solution: Add ||
with default value.
<input checked={state.bestSellerOnly || false} id="best-seller" type="checkbox" value="" className="" />
Here state.bestSellerOnly
might return undefined at the time of mounting that can cause a warning for react.
Upvotes: 4
Reputation: 3689
Actually in react when you are facing this, it is an error of controlled and uncontrolled components, in Simple words: controlled components: are the components which uses states to change their values. Example:
<input
onChange={(e)=>{whatever!}
value={from your state}
/>
while in uncontrolled components states are not involved that much you can simply use defaultValue or ref. Example:
<input
defaultValue={from your state or from anywhere}
/>
Remember: if you are using both value and defaultValue it will give you the error because we can't use value of controlled component and defaultValue of uncontrolled component together.
Hint: you need to choose between controlled and uncontrolled components, so using ref would be solution for it. or Changing value to defaultValue will resolve it.
Note:
defaultValue
is only for the initial load. If you want to initialise the input then you should use defaultValue, but if you want to use state to change the value then you need to use value. Read this for more React input defaultValue doesn't update with state
I used the below way in the input to get rid of that warning,define the value property by using Short-circuit evaluation like this:
value={this.state.fields.name || ''} // (undefined || '') = ''
Another Approach
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 Solution:
1- Define the fields
in state as:
this.state = { fields: {name: ''} }
Upvotes: 15
Reputation: 63524
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>
Upvotes: 3