39

I've a series of user data elements which I'm collecting inside a React component using hooks.

const [mobile, setMobile] = useState('');
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');

Each of these are updated as follows.

<input type="text"
       className="form-control"
       id="mobile"
       placeholder="Enter a valid mobile number"
       onChange={event => {setMobile(event.target.value)}}/>

Is there a more succint way to do this using an object as the variable?

Liam
  • 27,717
  • 28
  • 128
  • 190
Melissa Stewart
  • 3,483
  • 11
  • 49
  • 88

3 Answers3

81

You should add name attributes to input tags. Each name must refer to key in AllValues object.

const [allValues, setAllValues] = useState({
   mobile: '',
   username: '',
   email: '',
   password: '',
   confirmPassword: ''
});
const changeHandler = e => {
   setAllValues({...allValues, [e.target.name]: e.target.value})
}
return (
   <input type="text"
       className="form-control"
       id="mobile"
       name="mobile"
       placeholder="Enter a valid mobile number"
       onChange={changeHandler}
   />
   // ...
)
Shotiko Topchishvili
  • 2,663
  • 10
  • 20
21

The above answer could create issues in some cases, the following should be the right approach.

const [allValues, setAllValues] = useState({
   mobile: '',
   username: '',
   email: '',
   password: '',
   confirmPassword: ''
});
const changeHandler = e => {
   setAllValues( prevValues => {
   return { ...prevValues,[e.target.name]: e.target.value}
}
}
Rijo Joy
  • 335
  • 3
  • 6
  • 1
    This should be safe more than the accepted answer. I have experienced some tricky bugs and this answer solved that problem. – Thanh Nguyen Jul 18 '21 at 08:07
  • For React 16 and earlier, this might cause a problem because of Event Pooling. Be sure to use this only for React 17 or later. Note that you can still use this answer with some additional lines like <_name=e.target.name;_value=e.target.value> and using _name and _value instead of using e directly in the return phrase. – JM217 Aug 28 '21 at 08:34
7

Set initial values

const initialValues = {                   // type all the fields you need
name: '',
email: '',
password: ''
};

UseState

const [values, setValues] = useState(initialValues);       // set initial state

Handling the changes

const handleChange = (e) => {                
  setValues({
    ...values,                                // spreading the unchanged values
    [e.target.name]: e.target.value,          // changing the state of *changed value*
  });
};

Making the Form

<form>
  <input type="email"
   id="xyz"
   name="email"                                     // using name, value, onChange for applying changes
   value={email}
   onChange={changeHandler}
   placeholder="Enter your email"
   />
   // other inputs
</form>
confused_
  • 1,133
  • 8
  • 10