-3

React code:

const [state, setState] = useState({login:'', password: ''});

const changeHandler  = (e) =>{
    setState({[e.target.name]: e.target.value});
}

return(
    <div className='login-wrapper'>
        <form onSubmit={(e) => submitHandler(e)}>

            <Input color='primary'
                   margin='dense'
                   placeholder='login'
                   type='text'
                   style={{margin:'20px', width:'300px'}}
                   name='login'
                   value={state.login}
                   onChange={(e) => changeHandler(e)}/>
       </form>
  </div>)}

Error:

A component is changing a controlled input of type password to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

Filburt
  • 17,626
  • 12
  • 64
  • 115
Naira
  • 3
  • 1
  • Problem is fromm this part of code setState({[e.target.name]: e.target.value}); – Naira Jul 20 '20 at 19:21
  • 1
    Have a look at this: https://stackoverflow.com/questions/47012169/a-component-is-changing-an-uncontrolled-input-of-type-text-to-be-controlled-erro – tdranv Jul 20 '20 at 19:26
  • What is `Input`? Does it expect the same props as a normal `input`? – Brian Thompson Jul 20 '20 at 19:39
  • If `Input` does not pass the `name` to the underlying `input` element, `e.target.name` will be undefined. That may not be the issues, but its a possibility. – Brian Thompson Jul 20 '20 at 19:43
  • yes, it is input I've used material-ui, that's why it is in capital letter – Naira Jul 20 '20 at 19:44
  • in console I see the result of e.target.name and e.target.value separately․ But in this expression it doesn't work setState({[e.target.name]: e.target.value}); – Naira Jul 20 '20 at 19:47

2 Answers2

0

e.target.name is probably coming through as undefined, so value={state.login} as a prop returns undefined, which switches the component to non-controlled.

Fix with this:

const loginChangeHandler = (e) => setState({...state, login: e.target.value});

Luke Storry
  • 6,032
  • 1
  • 9
  • 22
0

From the docs on useState:

Unlike this.setState in a class, updating a state variable always replaces it instead of merging it.

If you use an object as the value of a useState hook, an update to it must replace all values.

What is happening is you are updating login, but not replacing password. So the password input is presumably the one throwing the warning. The password was set to a string, then it becomes undefined.

The solution is simple, spread the previous state values into the new object before updating it:

setState({...state, [e.target.name]: e.target.value});

The most optimal change handler would also take advantage of the functional form of the updater and look something like this:

// Destructure the event for cleaner syntax and avoiding the pitfall of pooled events
const changeHandler  = ({ target: {name, value} }) => {
  // Use a functional update to ensure we always have the most recent copy of state
  setState(prev => ({ ...prev, [name]: value }));
}
Brian Thompson
  • 13,263
  • 4
  • 23
  • 43