62

I want to provide default values in the input field using react-hook-form. First I retrieve the user data from the API endpoint and then setting the state users to that user data. Then I pass the state users to the defaultValues of useForm().

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

function LoginFile() {
  const [users, setUsers] = useState(null);

  useEffect(() => {
    axios
      .get("http://localhost:4000/users/1")
      .then((res) => setUsers(res.data));
  }, []);

  useEffect(() => {
    console.log(users);
  }, [users]);

  const { register, handleSubmit, errors } = useForm({
    defaultValues: users,
  });
 return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        Email <input type="email" name="email" ref={register} /><br />
        firstname <input name="firstname" ref={register} /><br/>
        <input type="submit" />
      </form>
    </div>
 );
}
export default LoginFile;

I did by the above code but didn't work as expected. All the input fields are still empty. I want to have some default values in the input field of my form.

4 Answers 4

96

The problem is that during the first render, users is the useState hook's initial value, which is null. The value only changes after the axios.get() request finishes, which is after the initial render. This means that the the default values passed to useForm is null.

The documentation for defaultValues says the following:

defaultValues are cached on the first render within the custom hook. If you want to reset the defaultValues, you should use the reset api.

So, you'll just need to use reset to reset the form manually to the values which you fetch. The documentation for reset says the following:

You will need to pass defaultValues to useForm in order to reset the Controller components' value.

However, it's unclear from the documentation whether null is enough as the defaultValues, or if you need to pass it a proper object with fields for each input. To play it safe, let's assume it's the latter.

The code for doing this would look something like this:

function LoginFile() {
  const [users, setUsers] = useState({ email: "", firstname: "" });

  const { register, handleSubmit, errors, reset } = useForm({
    defaultValues: users,
  });

  useEffect(() => {
    axios.get("http://localhost:4000/users/1").then((res) => {
      setUsers(res.data);
      reset(res.data);
    });
  }, [reset]);

  useEffect(() => {
    console.log(users);
  }, [users]);

  return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        Email <input type="email" name="email" ref={register} />
        <br />
        firstname <input name="firstname" ref={register} />
        <br />
        <input type="submit" />
      </form>
    </div>
  );
}

Additionally, if the only reason for the useState hook is to store the value for defaultValues, you don't need it at all and can clean up the code to be:

function LoginFile() {
  const { register, handleSubmit, errors, reset } = useForm({
    defaultValues: { email: "", firstname: "" },
  });

  useEffect(() => {
    axios.get("http://localhost:4000/users/1").then((res) => {
      reset(res.data);
    });
  }, [reset]);

  return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        Email <input type="email" name="email" ref={register} />
        <br />
        firstname <input name="firstname" ref={register} />
        <br />
        <input type="submit" />
      </form>
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

6 Comments

Will reset(res.data) resets the defaultValue to the API users data like {email: "[email protected]", firstname: "subrato"}? I am asking this bcz my mindset is that reset means empty the input field.
The documentation for reset says: "You can pass values as an optional argument to reset your form into the assigned default values.".
I have id key in my user's data. What will be the defaultValue of id when we defining them in useForm? Is it okay with {id: 0, email; "", firstname:""}? I am using your first approach.
Yeah, this work. I have noticed one thing that I like to share when I set the state as null It is showing me an error like cannot read property of "email" which is null' but when I set the state as [] then it shows empty values to the input fields
You are a hero!
|
15

That definitely Worked. Using the reset API and the UseEffect.

Starting with empty stings as default values and the updating them as effects with the reset. Here is my code. Was using TypeScript with Ionic here as well...

const { control: editControl, handleSubmit: editSubmit, reset } = useForm<EditFormType>({
      defaultValues: {
         question: "",
         optionA: "",
         optionB: "",
         optionC: "",
         optionD: "",
      }
   });

   useEffect(() => {
      let defaults ={
         question: editQuestion?.body,
         optionA: editQuestion?.options[0].body,
         optionB: editQuestion?.options[1].body,
         optionC: editQuestion?.options[2].body,
         optionD: editQuestion?.options[3].body,
      }
      reset(defaults)
   }, [editQuestion, reset])

2 Comments

This answer was easier to follow for my problem because it didn't have all the extra noise of the other answer.
Specifying defaultValues for useForm may not be necessary.
3

For this use case, you need to use the values parameter instead of default values. The other answers work but are more complex. Checkout the documentation on useForm. values is reactive meaning it will apply changes when the API call changes users

Your code should look like this

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

function LoginFile() {
  const [users, setUsers] = useState(null);

  useEffect(() => {
    axios
      .get("http://localhost:4000/users/1")
      .then((res) => setUsers(res.data));
  }, []);

  const { register, handleSubmit, errors } = useForm({
    values: users,
  });
 return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        Email <input type="email" name="email" ref={register} /><br />
        firstname <input name="firstname" ref={register} /><br/>
        <input type="submit" />
      </form>
    </div>
 );
}
export default LoginFile;

Comments

1

I will just explain my findings here, we must set defaultValue in order for reset to work, and also to get get correct isdirty value or to reset isDirty value when value reset to default. To set defaultValue, we have options to set defaultValue with useForm or use reset or resetField inside useEffect hook. Note- setValue will not set default value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.