如何使用 useEffect() 更改 React-Hook-Form defaultValue?
Posted
技术标签:
【中文标题】如何使用 useEffect() 更改 React-Hook-Form defaultValue?【英文标题】:How to change React-Hook-Form defaultValue with useEffect()? 【发布时间】:2020-09-26 06:32:39 【问题描述】:我正在创建一个页面供用户使用 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
,但它也不起作用。
我上面的代码有什么问题吗?
【问题讨论】:
对不起,我没明白你想达到什么目的,你能解释一下吗? 【参考方案1】:您可以使用 setValue (https://react-hook-form.com/api/useform/setvalue)。
从 useForm 导入:
const handleSubmit, control, setValue = useForm( mode: 'onBlur' );
然后在收到用户数据后调用它:
useEffect(() =>
if (userData)
setValue([
name: userData.name ,
phone: userData.phone
]);
, [userData]);
您可以从表单中删除默认值。
编辑:如果这不起作用,请参阅下面的替代答案。
【讨论】:
一次为所有 FormValues 寻找 setValue 的 typescript 版本 @tommcandrew 你说得对,但我们仍然需要在表单中添加 defaultValues。 setValue 如何用于复选框和单选按钮? 对我不起作用。得到路径拆分错误。宁可回答下面的工作。【参考方案2】:setValue
对我不起作用。或者,您可以使用reset
方法:
重置整个表单状态或部分表单状态。
这是工作代码:
/* 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]);
【讨论】:
【参考方案3】:@tommcandrew 的 setValue 参数格式对我不起作用。
这种格式做到了:
useEffect(() =>
const object = localStorage.getItem('object');
setValue("name", object.name);
, [])
【讨论】:
这适用于我的 React Native 和控制器包装器。 终于。我做到了。谢谢兄弟【参考方案4】:虽然这篇文章已经发布了 2 个月,但我今天偶然发现了这个问题,并寻找了几种方法来解决这个问题。我想出的最有效的方法是使用 useMemo 来设置你的 defaultValues,像这样:
const control, errors, handleSubmit = useForm(
reValidateMode: 'onChange',
defaultValues: useMemo(() => yourDefaultValues, [yourDefaultValues]),
);
这使您可以在表单中正确设置值,如果您碰巧有字段数组(这是我的情况),则无需进行多种实现。
这也适用于使用官方文档中的advanced smart form component exemple。如果您有任何问题,请告诉我!
【讨论】:
我在 6.8.3 上运行,每次yourDefaultValues
更改时都会重新评估默认值,但表单上没有任何反应(我在 useMemo 中添加了调试语句)。我已验证该名称与组件的name
相同,并且组件使用inputRef
和register
。你有什么想法吗?
复制链接:codesandbox.io/s/usereacthookformdefaultvalue-h6d71?file=/src/…【参考方案5】:
@tam 的答案已经完成了使其与 6.8.3 版一起工作所需的一半。
你需要提供默认值还要使用Effect来重置。如果您有一个与另一个实体一起重新加载的表单,则需要这种特殊的区别。我在CodeSanbox here 中有一个完整的例子。
简而言之:
您需要在 userForm
中定义您的 defaultValues。
const register, reset, handleSubmit = useForm(
defaultValues: useMemo(() =>
return props.user;
, [props])
);
那么你需要倾听潜在的变化。
useEffect(() =>
reset(props.user);
, [props.user]);
代码沙箱中的示例允许在两个用户之间进行交换并让表单更改其值。
【讨论】:
这绝对是这里最干净的答案之一。 @帕特里克,这行得通。只是一个疑问,当我尝试不包装 useMemo 时它也起作用了,我们使用 useMemo 的原因是它不会在下一次渲染时重新计算,除非任何依赖项发生变化。还有任何其他使用 useMemo 且不使用 useMemo 直接传递对象的差异,因为 useEffect 已经存在?如果这个错误你能纠正我吗?新反应:) 只是好奇你为什么在这里使用 useMemo? 这是正确的。【参考方案6】:这适用于嵌套对象(我使用的是 6.15.1 版)
useEffect(() =>
for (const [key, value] of Object.entries(data))
setValue(key, value,
shouldValidate: true,
shouldDirty: true
)
, [data])
【讨论】:
最干净的实现 imo 虽然,eslint 不喜欢for of
循环。一个可能的解决方案是Object.keys(data).forEach((val, i) => )
【参考方案7】:
找到另一种简单的方法,我使用了 useForm 中的reset
API
const handleSubmit, register, reset = useForm( resolver );
调用API取回响应数据后,用新的apiData调用reset
,确保apiData键与输入键相同(名称属性):
useEffect(() =>
reset(apiData);
, [apiData]);
表单的默认值被缓存,因此一旦您从 API 获取数据,我们就会使用新数据重置表单状态。
【讨论】:
以上是关于如何使用 useEffect() 更改 React-Hook-Form defaultValue?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用/不使用 useEffect 钩子在 React JS 函数中获取更改的(新)状态值?
如何停止 React.useEffect 的副作用? [复制]