Muhammad Osama
Muhammad Osama

Reputation: 1047

Set default values in react-hook-form conditionally

Background:
I have a very long complex form with deep nested objects creating using rhf (react-hook-form). I want to provide a checkbox at the top of the form which toggles the default values in the fields to assist the user.

Problem
By using rhf, I was able to fill up the defaultValues using reset method but now the issue is once I call the reset method with the defaultValues, I can't unset the values using the reset if I provide an empty object.

Things I've tried
I've tried using the setValue method but it unset only 1 field at once and it'll require recursion to set values for deep-nested object.

Code
Here's a very minimal example of what I'm trying to do.

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { useForm } from "react-hook-form";

const defaultValues = { name: `John Doe` };

const Form = () => {
  const [useDefaultValues, setUseDefaultValues] = useState(false);
  const { register, handleSubmit, reset } = useForm();

  useEffect(() => {
    if (useDefaultValues) {
      reset(defaultValues);
    } else {
      reset({}, { keepValues: false, keepDefaultValues: false });
    }
  }, [useDefaultValues]);

  return (
    <>
      <label>
        <input
          type="checkbox"
          value={useDefaultValues}
          onChange={() => setUseDefaultValues((prev) => !prev)}
        />
        Use Default values
      </label>
      <form onSubmit={handleSubmit}>
        <div>
          <label>Name</label>
          <input type="text" name="name" {...register("name")} />
        </div>
        <input type="submit" />
      </form>
    </>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Form />, rootElement);

Codesandbox: https://codesandbox.io/p/sandbox/react-hook-form-reset-form-forked-sxmy8q?file=%2Fsrc%2Findex.js%3A1%2C1-42%2C1

Notice how unsetting the defaultValues doesn't empty the form again

Upvotes: 0

Views: 2717

Answers (1)

Muneeb Khan
Muneeb Khan

Reputation: 273

Your form need to have 3 states. First one containing the default values. Second one need to have empty value (actual reset). Third one need to have actual(current) values which will be handled by react hook form.

An optional object to reset form values, and it's recommended to provide the entire defaultValues when supplied. Source

The Solution to the your Code:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { useForm } from "react-hook-form";

const defaultValues = { name: `John Doe` }; // your own default values

const Form = () => {
  const [useDefaultValues, setUseDefaultValues] = useState(false);
  const { register, handleSubmit, reset } = useForm({
    defaultValues: { name: `` },
  }); // actual empty defaul values, you can provide here

  useEffect(() => {
    if (useDefaultValues) {
      reset(defaultValues, { keepValues: false, keepDefaultValues: true }); // reset to defaultValues provided above
    } else {
      reset(); // reset to actual empty defaul values
    }
  }, [useDefaultValues]);

  return (
    <>
      <label>
        <input
          type="checkbox"
          value={useDefaultValues}
          onChange={() => setUseDefaultValues((prev) => !prev)}
        />
        Use Default values
      </label>
      <form onSubmit={handleSubmit}>
        <div>
          <label>Name</label>
          <input type="text" name="name" {...register("name")} />
        </div>
        <input type="submit" />
      </form>
    </>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Form />, rootElement);

keepValues(true):

Form input values will remain unchanged. Let say we changed the name to 'abc' then we call

reset(newValues, { keepValues: true });

The form will still have the old values. The newValues given here would have no effect.

On the other hand, if we have keepValues(false) the value will become equal to the newValues provided in the reset function otherwise (if empty object provided) it become default values.

keepDefaultValues(true):

The form values given in the reset function become the default values. In order to identify any change in the state of the form we use isDirty. If we have keepDefaultValues(true), the isDirty will compare the default value with the current form value to tell whether the form state has changed or not.

On the other hand, if we have keepDefaultValues(false), the isDirty will compare the new given value in the reset function with the current form value to tell whether the form state has changed or not.

In simple words in addition to this use case, the keepDefaultValues fucntion can be useful if we want to keep the Default value same as we provided in the beginning by using keepDefaultValues(true).

Upvotes: 0

Related Questions