DEV Community

Alejo Garcia
Alejo Garcia

Posted on • Originally published at reactshark.com

Form Refactoring with useReducer React Hook (mini guide)

In this article, you are going to see a practical approach on how you can implement useReducer, and it also introduces the idea of reducer, so it's beginner-friendly!

So we have this form

import {
  FormControl,
  FormLabel,
  FormHelperText,
  Input,
    Button
} from "@chakra-ui/react";
const Form = () => {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  return (
    <FormControl id="form" p={50}>
      <FormLabel>First and last name</FormLabel>
      <Input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <FormLabel>Email address</FormLabel>
      <Input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <FormHelperText>We'll never share your email.</FormHelperText>
      <FormLabel>Password</FormLabel>
      <Input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
            <Button mt={4} colorScheme="teal" type="submit">
        Login
      </Button>
    </FormControl>
  );
};
export default Form;
Enter fullscreen mode Exit fullscreen mode

We are using Chakra UI, a React library, and in case you don't know how to install it, go here.

So the first thing we want to do is to create our initialState.

This will be an object containing our 3 states: name, email and password.

const initialState = {
  name : '',
  email : '',
  password : ''
}

const Form = () => {
...
}
Enter fullscreen mode Exit fullscreen mode

Now import the useReducer hook

import { useState, useReducer } from "react";
Enter fullscreen mode Exit fullscreen mode

So here comes the new part for you if you are just learning the concept of reducer.

We are going to create a separate file called reducer.js where it will have a function that handles our state.

// reducer.js

function reducer (state, action) {

}

Enter fullscreen mode Exit fullscreen mode

As you can see we take two parameters:

  1. state this will be the state we receive from the dispatch method that was executed in our case from App.js
  2. action someone calls it the actionObject because when dispatched it looks like this:
const action = {
    type: 'FETCH'
        data : "Alejo"
  };
Enter fullscreen mode Exit fullscreen mode

Continuing with the reducer function, now lets build our switch cases

 function reducer (state, action) {
  switch(action.type){
    case "UPDATE" :
      return {
        ...state,
        [action.key] : action.value
      }
         default:
        return state
  }
}
Enter fullscreen mode Exit fullscreen mode

So what's going on here?

The switch statement, which will be in charge of aligning the action.type to the changes the reducer is going to implement. In other words, the switch will determine those changes like modifying the state BASED on the value of the action.type

Are you getting it now?

The spread operator is ...state and what it does is basically copying the entire state, in order to only modify only the [action.key] : action.value

Having explained the above, now let's add the reducer function into the App.js component

import reducer from "./reducer"
import { useState, useReducer } from "react";

const initialState = {
  name: "",
  email: "",
  password: ""
};

const Form = () => {
// const [name, setName] = useState("");
// const [email, setEmail] = useState("");
// const [password, setPassword] = useState("");

const [reducerState, dispatch] = useReducer(reducer, initialState);

...
}
Enter fullscreen mode Exit fullscreen mode

Following that we are going to change value of our input from the useState, to the initialState and change the onChange setting state functions to the reducer ones using dispatch.

<Input
        type="text"
        value={reducerState.name}
        onChange={(e) =>
          dispatch({
            type: "UPDATE",
            value: e.target.value,
            key: "name"
          })
        }
      />
Enter fullscreen mode Exit fullscreen mode
        <Input
        type="email"
        value={reducerState.email}
        onChange={(e) =>
          dispatch({
            type: "UPDATE",
            value: e.target.value,
            key: "email"
          })
        }
      />
Enter fullscreen mode Exit fullscreen mode
    <Input
        type="password"
        value={reducerState.password}
        onChange={(e) =>
          dispatch({
            type: "UPDATE",
            value: e.target.value,
            key: "password"
          })
        }
      />
Enter fullscreen mode Exit fullscreen mode

Final step

Let's create a console.log inside a submit() function, so we get to see the complete state from the reducer, and confirm that we have refactored the form successfully:

const Form = () => {

  function submit() {
    console.log({
      name: reducerState.name,
      email: reducerState.email,
      password: reducerState.password
    });
  }
  return (
          ...
      <Button onClick={() => submit()} mt={4} colorScheme="teal" type="submit">
        Login
      </Button>
  );
};
export default Form;
Enter fullscreen mode Exit fullscreen mode

OUTPUT:

{name: 'asadsasd', email: 'adsda@gmail.com', password: 'sadadada'}

Success! Now you have a React form working with useReducer

Complete refactored form code:

Couldn't post a Github repo, but you can check its CodeSandbox.

// App.js
import {
  FormControl,
  FormLabel,
  FormHelperText,
  Input,
  Button
} from "@chakra-ui/react";
import reducer from "./reducer";
import { useState, useReducer } from "react";
const initialState = {
  name: "",
  email: "",
  password: ""
};

const Form = () => {
  const [reducerState, dispatch] = useReducer(reducer, initialState);

  function submit() {
    console.log({
      name: reducerState.name,
      email: reducerState.email,
      password: reducerState.password
    });
  }
  return (
    <FormControl id="form" p={50}>
      <FormLabel>First and last name</FormLabel>
      <Input
        type="text"
        value={reducerState.name}
        onChange={(e) =>
          dispatch({
            type: "UPDATE",
            value: e.target.value,
            key: "name"
          })
        }
      />
      <FormLabel>Email address</FormLabel>
      <Input
        type="email"
        value={reducerState.email}
        onChange={(e) =>
          dispatch({
            type: "UPDATE",
            value: e.target.value,
            key: "email"
          })
        }
      />
      <FormHelperText>We'll never share your email.</FormHelperText>
      <FormLabel>Password</FormLabel>
      <Input
        type="password"
        value={reducerState.password}
        onChange={(e) =>
          dispatch({
            type: "UPDATE",
            value: e.target.value,
            key: "password"
          })
        }
      />
      <Button onClick={() => submit()} mt={4} colorScheme="teal" type="submit">
        Login
      </Button>
    </FormControl>
  );
};
export default Form;
Enter fullscreen mode Exit fullscreen mode
// reducer.js

function reducer (state, action) {
  switch(action.type){
    case "UPDATE" :
      return {
        ...state,
        [action.key] : action.value
      }
      default:
        return state
  }
}
export default reducer
Enter fullscreen mode Exit fullscreen mode

This article was published originally in React Shark's blog:

https://www.reactshark.com/blog/form-refactor-with-usereducer

Top comments (0)