Create a Custom React Hook to Handle Form Fields

Link to chapter - https://serverless-stack.com/chapters/create-a-custom-react-hook-to-handle-form-fields.html

Question-- How would you go about clearing all of the fields in that custom hook? For example, you could have a form where a user could want to submit multiple times; how could you use this hook to easily set each field to an empty string?

1 Like

That’s a good question. For that I would return another function with the hook that resets the state to the initialState.

I don’t understand the event.target line in the custom React hook:

setValues({
    ...fields,
    [event.target.id]: event.target.value
  });

Why assign event.target.value to event.target.id?

The explanation is:

The only difference here is that we are using event.target.id (which contains the id of our form field) to store the value ( event.target.value ).

I still don’t get it.

Ah, I added a note and edited the chapter. Hope that helps.

In the case of our form the elements, the event.target.id is set as the the controlId. So we are using that as the id in our state.

<FormGroup controlId="email" bsSize="large">
 <ControlLabel>Email</ControlLabel>
 <FormControl
   autoFocus
   type="email"
   value={email}
   onChange={e => setEmail(e.target.value)}
 />
</FormGroup>
1 Like

Got it. So in the state object we end up with a property called “email” that has the value of what the user entered in the form. Thanks!

MS Edge still doesn’t support the es6 spread operator. Therefore this hook will cause the following error: SCRIPT1028 “Expected identifier, string or number”

Whoa that’s weird. Can somebody else confirm this?

How about add react-app-polyfill?

How do you reset the values, let’s say after form submit?

It would take a bit more code. But it might work something like this (haven’t quite tested this yet):

export function useFormFields(initialState) {
  const [fields, setValues] = useState(initialState);

  return [
    fields,
    function(event) {
      setValues({
        ...fields,
        [event.target.id]: event.target.value
      });
    },
    function () {
      setValues({ ...fields });
    }
  ];
}

Here the third parameter returned is a reset function. If it’s called, it would reset the fields. However, if you are going to have more than 2 returned values in an array, it would be more descriptive to return it as an object.

I might be having a slow day but it took me a while to understand how this hook works.
I think a comment like this could help:

“useState can set multiple values at once when passed an array, or it can set a single value when passed just one value. The setValues function returned by useState can update multiple values or just a single value. We pass a single key:value pair when used with the onChange event.”

1 Like

Thanks for this! I update the chapter with a better description of how this hook works.

1 Like

Cool thanks, hope that helps someone else out there too.

1 Like

If anyone wants to add the ability for their hook to handle a checkbox, which I found handy as I wanted to add a privacy policy checkbox to the form upon registration

import { useState } from "react";

export function useFormFields(initialState) {
  const [fields, setValues] = useState(initialState);
  let ret =  [
    fields,
    function(event) {
      let value = (event.target.type == 'checkbox')?event.target.checked:event.target.value;
     setValues({
        ...fields,
        [event.target.id]: value
      });
    }
  ];
  return ret;
}

Id like to figure out how to do this as well

How would you call the reset function?

Make sure to add the reset function here const [fields, handleFieldChange, reset] = useFormFields... and then call it when you need it.