如何使用 useEffect() 更改 React-Hook-Form defaultValue?

IT技术 javascript reactjs react-hooks react-hook-form
2021-04-20 13:42:34

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

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

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 运行良好,并且该值实际上已设置为userDatastate。

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

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

6个回答

您可以使用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]);

您可以从表单中删除默认值。

编辑:如果这不起作用,请参阅下面的替代答案。

@tommcandrew 你是对的,但我们仍然需要在表单中添加 defaultValues。
2021-06-03 13:42:34
一次为所有 FormValues 寻找 setValue 的typescript版本
2021-06-08 13:42:34
setValue 如何用于复选框和单选按钮?
2021-06-16 13:42:34
对我不起作用。得到路径分割错误。而是下面的答案有效。
2021-06-20 13:42:34

@tam 的回答是使其与版本 6.8.3 一起工作所需的一半。

您需要提供默认值还要使用效果来重置。如果您有一个用另一个实体重新加载的表单,则需要这种特殊的区别。我在CodeSanbox 这里有一个完整的例子

简而言之: 您需要在userForm.

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

然后你需要倾听潜在的变化。

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

Code Sandbox 中的示例允许在两个用户之间进行交换并让表单更改其值。

这是对的。
2021-05-22 13:42:34
只是好奇你为什么在这里使用 useMemo?
2021-05-25 13:42:34
@帕特里克,这有效。值得怀疑的是,当我尝试不包含在 useMemo 中时它也有效,我们使用 useMemo 的原因是它不会在下一次渲染时重新计算,除非任何依赖项发生变化。还有任何其他使用 useMemo 而没有使用 useMemo 直接传递对象的差异,因为 useEffect 已经存在?如果这是错误的,你能纠正我吗 - 新来的反应:)
2021-06-06 13:42:34
这绝对是这里更简洁的答案之一。
2021-06-16 13:42:34

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]); 

@tommcandrew 的setValue参数格式对我不起作用。

这种格式做了:

useEffect(() => {
  const object = localStorage.getItem('object');
  setValue("name", object.name);
}, [])
这对我来说适用于 React Native 和控制器包装器。
2021-05-27 13:42:34
最后。我做的。多谢兄弟
2021-06-02 13:42:34

虽然这篇文章已经发布了 2 个月,但我今天偶然发现了这个问题,并寻找了几种方法来解决这个问题。我想出的最有效的方法是使用 useMemo 来设置默认值,如下所示:

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

这允许您在表单中正确设置值,如果您碰巧有字段数组(这就是我的情况),则无需进行多次实现的斗争。

这也适用于使用官方文档中高级智能表单组件示例如果您有任何问题,请告诉我!

我在 6.8.3 上运行,每次yourDefaultValues更改时都会重新评估默认值,但表单上没有任何反应(我在 useMemo 中添加了调试语句)。我已验证名称name与组件的名称相同,并且组件正在使用inputRefregister你有什么主意吗?
2021-05-24 13:42:34