admin管理员组文章数量:1128437
I am creating a page for user to update personal data with React-Hook-Form.
Once paged is loaded, I use useEffect
to fetch the user's current personal data and set them into default value of the form.
I put the fetched value into defaultValue
of <Controller />
.
However, it is just not showing in the text box.
Here is my code:
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;
I am creating a page for user to update personal data with React-Hook-Form.
Once paged is loaded, I use useEffect
to fetch the user's current personal data and set them into default value of the form.
I put the fetched value into defaultValue
of <Controller />
.
However, it is just not showing in the text box.
Here is my code:
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;
The called API is working well and the value is actually set to userData
state.
{
name: "John",
phone: "02-98541566"
...
}
I also tried to setUserData
with mock data in useEffect()
, and it doesn't work either.
Is there any problem in my above code?
- sorry but i didn't get what are you trying to achieve can you explain more. – adel Commented Jun 7, 2020 at 8:57
18 Answers
Reset to default 201@tam's answer is halfway to 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 useForm
:
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.
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]);
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.
@tommcandrew's setValue parameter formatting didn't work for me.
This format did:
useEffect(() => {
const object = localStorage.getItem('object');
setValue("name", object.name);
}, [])
I know this post is a few years old but I stumbled upon it and found that there is now a better way than the accepted answer.
The documentation now has a prop called values
that will reactively update (see https://react-hook-form.com/docs/useform#values).
Here is the example code:
function App() {
const values = useFetch("/api")
useForm({
defaultValues: {
firstName: "",
lastName: "",
},
values, // will get updated once values returns, this can be a state variable like OP's userData state variable.
})
}
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 !
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])
As of react-hook-form 7.41, you can use defaultValues with async functions like this:
const {
formState: { isLoading },
} = useForm({
defaultValues: fetch('API'),
// resetOptions: {
// keepDirtyValues: true
// }
});
now the defaultValue field type look like this:
type AsyncDefaultValues<TFieldValues> = (payload?: unknown) => Promise<TFieldValues>;
isLoading for the async defaultValues loading state.
Using reset
is a simple solution.
const { reset } = useForm();
onClick={()=> reset({ firstname: 'Joe' }, { lastname: 'Doe' }) }
Documentation mentions a way to set the default values if the state changes here https://react-hook-form.com/api/useform/#values
function App({ values }) {
useForm({
values // will get updated when values props updates
})
}
I have had issues reseting the form using above method, as it is leading to an infinite loop.
react hook form Maximum update depth exceeded
So, instead i tried to reset these values using useEffect, but still it did not worked.
Now, i realised that if i have to reset entire form, then i have did something like below and it worked.
useEffect(()=>{
reset({...dataFromApi});
}, [quote])
If you are using version 7, you may no longer need useEffect to do "loading defaultValue from async call (e.g. fetch)" on the form component mounts
example from v7.47 doc:
// set default value async
useForm({
defaultValues: async () => fetch('/api-endpoint');
})
note:
- that async function defined in
defaultValues
should return the object required fordefaultValues
- the call (
defaultValues()
) will be made on component mounts (same as useEffect with empty dependency array) - if you need other dependency, use
reset()
to load yourdefaultValues
(because they are cached)
There is a much better way to do this that I may have missed in the comments or in one of the answers.
Just send your defaultValues
in as a prop to the form itself.
This higher order pattern works quite a bit better.
<UpdateAppointmentForm defaultValues={query.data} />
When I fetch from my system, I have the model I'm working with populated. Passing it directly down to the function ensures it re-renders with the data in the way I need.
In the <UpdateAppointmentForm>
component, I can just use the useForm
hook with the values instantiated:
interface Props {
defaultValues: SchemaType;
}
export const UpdateAppointmentForm = (props: Props) => {
const form = useForm<SchemaType>({
resolver: zodResolver(Schema),
reValidateMode: "onBlur",
shouldFocusError: true,
defaultValues,
//...other stuff
});
// ... return your form
}
The approaches in here to manipulate the state on the fly just add unnecessary complication and other state juggling you really don't need to worry about. Let React's rendering cycle and component tree do the work for you.
Happy coding!
Easiest method for those interested,
// fetching data from clerk
const { user } = useUser();
// Creating default values based on information I am receiving from the parent component.
const defaultValues = initialData
? initialData
: {
name: "",
stock: 0,
description: '',
negotiable: false,
discount: 0,
categoryId: "",
creatorId: '',
isFeatured: false,
isArchived: false,
sizes: [],
colors: [],
price: 0,
images: [],
};
//I removed defaultValues from the form as this only renders the values into the hook form once. The 'values' function on the other hand re-renders on input change and asynchronously adds your data to the form. Also note that since the data being fetched is undefined at first, I had to give it a fallback value of an empty string.
const form = useForm<ProductFormValues>({
resolver: zodResolver(formSchema),
values: { ...defaultValues, creatorId: user?.id || '' },
});
Many comments telling you to just "setValue" or "reset". But that's not appropriate.
My recommendation:
Wrap you form in a Component, fetch the data on parent Component and render your form only when your data is ready. Use "defaultValues"
example:
const UserForm = ({data}) => {
const {...} = useForm({
defaultValues:data
})
}
const ParentForm = () => {
const userData = fetch('...');
return userData ? <UserForm data={userData} /> : <Loading />;
};
// single value change
useEffect(() => {
setValue("username", 'changed username', {
shouldValidate: true,
shouldDirty: true,
shouldTouch: true
})
}, []);
we can set the default values of hook forms using reset provided by react-hook-forms
const { handleSubmit, control,reset} = useForm();
const fetchUserData = useCallback(async account => {
const userData = await fetch(`${URL}/user/${account}`)
.then(res=> res);
console.log(userData);
if(userData.status===200||userData.status===201){
reset(userData.data);
}
}, []);
useEffect(() => {
const account = localStorage.getItem('account');
fetchUserData(account);
}, [fetchUserData])
this sets the values of the fields in form with the data fetched. this works only when the field names in both form and fetched matches. you can also specify the type of data for forms using interface if you are using typescript.
interface
interface props{
name:string,
id:number
}
useForm
const { handleSubmit, control,reset} = useForm<props>();
This solution worked for me
sessionData
is the result of fetching data
useEffect(() => {
sessionData &&
reset({
name: sessionData?.user?.name,
username: sessionData?.user?.username,
email: sessionData?.user?.emails.email,
password: "",
confirmPassword: "",
});
}, [sessionData]);
本文标签: javascriptHow to change ReactHookForm defaultValue with useEffect()Stack Overflow
版权声明:本文标题:javascript - How to change React-Hook-Form defaultValue with useEffect()? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736724622a1949657.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论