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

the*_*hen 35 javascript reactjs react-hooks react-hook-form

我正在创建一个页面供用户使用 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;
Run Code Online (Sandbox Code Playgroud)

被调用的 API 运行良好,值实际上设置为userDatastate。

{
  name: "John",
  phone: "02-98541566"
  ...
}
Run Code Online (Sandbox Code Playgroud)

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

小智 35

您可以使用setValue ( https://react-hook-form.com/api/useform/setvalue )。

从 useForm 导入:

    const { handleSubmit, control, setValue} = useForm({mode: 'onBlur'});
Run Code Online (Sandbox Code Playgroud)

然后在收到用户数据后调用它:

  useEffect(() => {
    if (userData) {
      setValue([{ name: userData.name }, { phone: userData.phone }]);
    }
  }, [userData]);
Run Code Online (Sandbox Code Playgroud)

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

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

  • 立即查找所有 FormValues 的 setValue 的打字稿版本 (2认同)
  • 我猜自从写完这个答案以来,“setValue”定义已经改变了。它现在采用单个名称和值,如“setValue(fieldName, fieldValue)”。设置单个字段适用于此方法;但不幸的是这不是目标。 (2认同)

Har*_*rni 34

找到了另一种简单的方法,我使用了resetuseForm 中的 API

 const { handleSubmit, register, reset } = useForm({ resolver });
Run Code Online (Sandbox Code Playgroud)

调用 API 并获取响应数据后,使用reset新的 apiData 进行调用,确保 apiData 键与输入键(名称属性)相同:

 useEffect(() => {
    reset(apiData);
  }, [apiData]);
Run Code Online (Sandbox Code Playgroud)

表单的默认值会被缓存,因此一旦您从 API 获取数据,我们就会使用新数据重置表单状态。


Pat*_*ins 26

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

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

简而言之: 您需要在userForm.

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

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

  useEffect(() => {
    reset(props.user);
  }, [props.user]);
Run Code Online (Sandbox Code Playgroud)

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

  • 只是好奇你为什么在这里使用 useMemo ? (10认同)
  • 这绝对是这里最干净的答案之一。 (8认同)

小智 20

setValue 对我不起作用。或者,您可以使用重置方法。我在下面分享一个工作代码块。我希望这个对你有用。

  ...
  /* 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: registeredAddresses[0].name,

        tel: registeredAddresses[0].contactNumber,
      });
    }
  }, [registeredAddresses]);

  ...
Run Code Online (Sandbox Code Playgroud)


gts*_*gts 12

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

这种格式做了:

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


小智 6

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

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

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

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


iMy*_*yke 6

这适用于嵌套对象(我使用的是 6.15.1 版)

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


Mer*_*ert 5

从react-hook-form 7.41开始,您可以将defaultValues与异步函数一起使用,如下所示:

const {
  formState: { isLoading },
} = useForm({
  defaultValues: fetch('API'),
  // resetOptions: {
  //   keepDirtyValues: true
  // }
});
Run Code Online (Sandbox Code Playgroud)

现在 defaultValue 字段类型如下所示:

type AsyncDefaultValues<TFieldValues> = (payload?: unknown) => Promise<TFieldValues>;
Run Code Online (Sandbox Code Playgroud)

isLoading用于异步 defaultValues 加载状态。