Dynamic Default Values in React Hook Form with useEffect
React Hook Form is a powerful library for managing form state and validation in React applications. But sometimes, you need your form fields to have default values that change dynamically based on external data or user interactions. This is where useEffect
comes in handy.
Let's imagine a scenario where you have a form to edit a user's profile. The initial values of the form should be fetched from the user's data, which is loaded asynchronously. Here's an example of how you might approach this:
import { useState, useEffect } from 'react';
import { useForm } from 'react-hook-form';
function UserProfileForm() {
const [userData, setUserData] = useState(null);
const { register, handleSubmit, setValue } = useForm();
useEffect(() => {
// Fetch user data from an API or another source
fetch('/api/users/current')
.then(res => res.json())
.then(data => setUserData(data));
}, []);
if (!userData) {
return <div>Loading user data...</div>;
}
const onSubmit = (data) => {
// Handle form submission here
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="name">Name:</label>
<input type="text" {...register('name')} defaultValue={userData.name} />
</div>
<div>
<label htmlFor="email">Email:</label>
<input type="email" {...register('email')} defaultValue={userData.email} />
</div>
<button type="submit">Save</button>
</form>
);
}
export default UserProfileForm;
In this example, we fetch user data using useEffect
and store it in the userData
state. Once the data is loaded, we use defaultValue
to populate the form fields with the retrieved information.
Why not directly set defaultValue
within useEffect
?
While it's tempting to set defaultValue
directly inside useEffect
, this approach has limitations:
- React Hook Form updates:
defaultValue
is only used for the initial rendering of the form. Subsequent changes in theuserData
state won't automatically update the form fields. - Performance impact: Repeatedly setting
defaultValue
withinuseEffect
can lead to unnecessary re-renders and impact performance, especially for larger forms with frequent data updates.
The setValue
solution:
Instead of relying on defaultValue
, the recommended approach is to utilize setValue
from React Hook Form. setValue
allows you to dynamically change the values of form fields after the initial rendering:
import { useState, useEffect } from 'react';
import { useForm } from 'react-hook-form';
function UserProfileForm() {
const [userData, setUserData] = useState(null);
const { register, handleSubmit, setValue } = useForm();
useEffect(() => {
fetch('/api/users/current')
.then(res => res.json())
.then(data => {
setUserData(data);
// Set default values for each field using setValue
setValue('name', data.name);
setValue('email', data.email);
});
}, []);
if (!userData) {
return <div>Loading user data...</div>;
}
const onSubmit = (data) => {
// Handle form submission here
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="name">Name:</label>
<input type="text" {...register('name')} />
</div>
<div>
<label htmlFor="email">Email:</label>
<input type="email" {...register('email')} />
</div>
<button type="submit">Save</button>
</form>
);
}
export default UserProfileForm;
This approach ensures that:
- Form fields are updated correctly:
setValue
updates the form's internal state, ensuring that all subsequent renders reflect the latest data. - Optimized performance:
setValue
is designed to efficiently update the form state without unnecessary re-renders.
By combining useEffect
and setValue
, you can create dynamic forms in React Hook Form that seamlessly adapt to changing data, enhancing the user experience and keeping your code clean and efficient.