如何使用 useEffect()更改 React-Hook-Form 默认值?

我正在创建一个页面,用户可以用 React-Hook-Form 更新个人数据。 一旦加载了分页,我就使用 useEffect来获取用户当前的个人数据,并将它们设置为表单的默认值。

我将提取的值放入 <Controller />defaultValue中。 但是,它只是没有显示在文本框中。 这是我的代码:

import React, {useState, useEffect, useCallback} from 'react';
import { useForm, Controller } from 'react-hook-form'
import { URL } from '../constants';


const UpdateUserData = props => {
const [userData, setUserData] = useState(null);
const { handleSubmit, control} = useForm({mode: 'onBlur'});


const fetchUserData = useCallback(async account => {
const userData = await fetch(`${URL}/user/${account}`)
.then(res=> res.json());
console.log(userData);
setUserData(userData);
}, []);


useEffect(() => {
const account = localStorage.getItem('account');
fetchUserData(account);
}, [fetchUserData])


const onSubmit = async (data) => {
// TODO
}


return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>User Name:</label>
<Controller
as={<input type='text' />}
control={control}
defaultValue={userData ? userData.name : ''}
name='name'
/>
</div>
                

<div>
<label>Phone:</label>
<Controller
as={<input type='text' />}
control={control}
defaultValue={userData ? userData.phone : ''}
name='phone'
/>
</div>
<button>Submit</button>
</form>
</div>
);
}


export default UpdateUserData;

被调用的 API 工作正常,值实际上被设置为 userData状态。

{
name: "John",
phone: "02-98541566"
...
}

我还尝试使用 useEffect()中的模拟数据使用 setUserData,但它也不能工作。 我上面的代码有什么问题吗?

127019 次浏览

You can use setValue (https://react-hook-form.com/api/useform/setvalue).

Import it from useForm:

const { handleSubmit, control, setValue} = useForm({ mode: 'onBlur' });

Then call it with the user data after it's received:

useEffect(() => {
if (userData) {
setValue([
{ name: userData.name },
{ phone: userData.phone }
]);
}
}, [userData]);

You can remove the default values from the form.

EDIT: See alternative answers below if this does not work.

setValue didn't work for me. Alternatively, you can use the reset method:

Reset either the entire form state or part of the form state.

Here is working code:

 /* registered address */
const [registeredAddresses, setRegisteredAddresses] = useState([]);


const { register, errors, handleSubmit, reset } = useForm <FormProps> ({
validationSchema: LoginSchema,
});


/**
* get addresses data
*/
const getRegisteredAddresses = async () => {
try {
const addresses = await AddressService.getAllAddress();
setRegisteredAddresses(addresses);
setDataFetching(false);
} catch (error) {
setDataFetching(false);
}
};


useEffect(() => {
getRegisteredAddresses();
}, []);


useEffect(() => {
if (registeredAddresses) {
reset({
addressName: registeredAddresses[0].name,
tel: registeredAddresses[0].contactNumber
});
}
}, [registeredAddresses]);

@tommcandrew's setValue parameter formatting didn't work for me.

This format did:

useEffect(() => {
const object = localStorage.getItem('object');
setValue("name", object.name);
}, [])

although this post is 2 months old, I stumbled upon this issue today and searched for a couple of ways to do it. The most effective way I've come up with is using useMemo to set your defaultValues, like this :

const { control, errors, handleSubmit } = useForm({
reValidateMode: 'onChange',
defaultValues: useMemo(() => yourDefaultValues, [yourDefaultValues]),
});

This allows you to properly set values in your form, without the struggle of multiple implementations if you happen to have field arrays (which was my case).

This also works while using the advanced smart form component exemple from the official documentation. Let me know if you have any questions !

@tam answer is halfway through what is needed to make it work with version 6.8.3.

You need to provide the default value but also to useEffect to reset. That particular distinction is required if you have a form that you reload with another entity. I have a complete example in CodeSanbox here.

In a nutshell: You need to define your defaultValues in the userForm.

 const { register, reset, handleSubmit } = useForm({
defaultValues: useMemo(() => {
return props.user;
}, [props])
});

Then you need to listen to potential change.

  useEffect(() => {
reset(props.user);
}, [props.user]);

The example in the Code Sandbox allows swapping between two users and have the form change its values.

This works for nested objects (I'm using version 6.15.1)

useEffect(() => {
for (const [key, value] of Object.entries(data)) {
setValue(key, value, {
shouldValidate: true,
shouldDirty: true
})
}
}, [data])

Found another easy way, I used reset API from useForm

 const { handleSubmit, register, reset } = useForm({ resolver });

After you call API and get back response data, you call reset with new apiData, make sure apiData key's are same as input keys (name attribute):

 useEffect(() => {
reset(apiData);
}, [apiData]);

form's default values are cached and hence once you get the data from API, we reset the form state with new data.

Using reset is a simple solution.

const { reset } = useForm();




onClick={()=> reset({ firstname: 'Joe' }, { lastname: 'Doe' }) }