简体   繁体   中英

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

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?

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: ''} }

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>

You could just pass defaultValue={value from state} . It worked for me.

This problem mainly occurs when you have an undefined value for an attribute, now it can checked for <input /> field or type or even value .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM