How To Efficiently Update React State For Multiple DOM Inputs Using the useReducer() Hook
Tags: react, javascript, webdev
Published: 2021-11-21 12:48:41

This article assumes some basic familiarity with the `useReducer()` hook. Examples are using `react-bootstrap` but you don't need to be using it in your own project for this to work.

#Efficient VS Inefficient
![HTML form with inputs for name and address](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkbvqdtwsrbtmmmu0vyp.png)
Any DOM structure of HTML inputs would do, but let's say for example you have an HTML form such as the one above. You want React to update state for every change of the input by the user.
##Inefficient
Assuming this state object...
```
  const initState = {
    firstName: "",
    lastName: "",
    street: "",
    aptSuite: "",
    city: "",
    stateName: "",
    zipcode: "",
    date: "",
    title: "",
    status: "fillingOutForm",
  };
```
Assuming a form input element structured like this...
```
<Form.Label htmlFor="user-first-name">First name</Form.Label>
  <Form.Control
    type="text"
    name="FIRSTNAME" // Used for the action type
    id="user-first-name"
    value={formState.firstName} // formState from useReducer
    required
    onChange={(e) => {
      const name = e.target.name;
      const value = e.target.value;
      dispatch({type: "CHANGE_" + name, payload: value });
    }}
/>
```
You could have a separate action type within the reducer function for each DOM input such as...
```
switch (type) {
  case CHANGE_FIRSTNAME:
    // Return modified state.
  case CHANGE_LASTNAME:
    // Return modified state.
  case CHANGE_STREET:
    // Return modified state.
  default:
    return state;
}
```
This is inefficient however.
##Efficient
The solution to this inefficiency is to abstract outwards in the reducer function.

Given this `onChange` handler...
```
// For example, the DOM input attribute name is 'firstName'
onChange={(e) => {
  const field = e.target.name;
  const value = e.target.value;

  dispatch({
    type: "CHANGE_INPUT",
    payload: {
      value,
      field,
    },
  });
}}
```
...the reducer function could contain this...
```
  function formReducer(state, action) {
    const { type, payload } = action;

    switch (type) {
      case "CHANGE_INPUT":
        return { ...state, [payload.field]: payload.value };
      default:
        return state;
    }
  }
```
*Normally one would have more cases in the reducer function but this example is simplified for educational purposes*

In the code above, a computed property name is used to take the attribute name of the element ('firstName') and update state in the right place. In this case...
```
const initState = {
  firstName: "Whatever was type in by user",
  // Rest of state properties...
}
```
#Gotchas
Remember how to access the data needed using computed property names. You need to wrap the dot notation object accessor for the action payload object in **brackets**.
`return { ...state, [payload.field]: payload.value };`
#Further Cleaning
Optimization of code length can be achieved by moving code from the `onChange()` handler to its own function. It might even be more descriptive to change the name to something like `updateStateWithInputValue`.
```
const changeDOMInput = (e) => {
  const field = e.target.name;
  const value = e.target.value;
  dispatch({
    type: "CHANGE_INPUT",
    payload: {
      value,
      field,
    },
  });
};

onChange={(e) => {
  changeDOMInput(e);
}}
```
I hope this helps!
#Connect With Me!
[www.kylewcode.com](https://www.kylewcode.com/)
[Twitter](https://twitter.com/kylewcode)
[LinkedIn](https://www.linkedin.com/in/85kylewilliams/)
[GitHub](https://github.com/kylewcode)