15

我尝试使用 react-hook-form 来验证输入。但是我发现,如果输入放在 Material UI 的对话框组件中,react-hook-formsetValue就不能按预期工作,但是当我删除 Dialog 组件时它可以工作。我猜原因是在组件挂载之前设置了值,但仍然找不到解决方案。

该值将从服务器检索,所以我不能使用 react-hook-form's defaultValues

https://codesandbox.io/s/react-hook-form-material-ui-twbbw

我曾尝试使用useState来控制输入值,但还有另一个问题。清除输入后,点击提交按钮,出现错误信息,输入的第一个字母I不会显示。

https://codesandbox.io/s/react-hook-form-material-ui-ve2en

4

5 回答 5

15

问题在于注册功能。在调用 Textfield 的 ref 后,您正在使用 register 注册 Textfield。

setValue在初始渲染后调用 useEffect 将名称设置为 123 。如果open为 true,则在 useEffect 之后呈现对话框内容。内容渲染完成后,调用带有寄存器的 ref 并将 Textfield(此处undefined)的默认值设置为 name 的值。

这就是为什么 Textfield 的值显示为 "" 的原因。您需要在调用 render 和 ref 回调后调用 setValue,以便该值保持不变。

您有两种选择:

  1. setTimeout在更改后使用异步延迟(或承诺)在useEffect 中设置值 async open。因此,如果您添加open到 useEffect 依赖数组并将值设置为异步,它就可以工作。这是一个沙盒
  2. 设置 Textfield 的默认值或将默认值添加到带有useForm({defaultValues: {name: '123}}).
于 2019-12-31T18:16:31.297 回答
5

对于外部控制元件

如果您使用的是 V3,我建议您使用react-hook-form-input https://github.com/react-hook-form/react-hook-form-input

import React from 'react';
import useForm from 'react-hook-form';
import { RHFInput } from 'react-hook-form-input';
import Select from 'react-select';

const options = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
];

function App() {
  const { handleSubmit, register, setValue, reset } = useForm();

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <RHFInput
        as={<Select options={options} />}
        rules={{ required: true }}
        name="reactSelect"
        register={register}
        setValue={setValue}
      />
      <button type="button">Reset Form</button>
      <button>submit</button>
    </form>
  );
}

如果您使用的是 V4,我建议您使用Controller https://react-hook-form.com/api/#Controller

import React from 'react';
import Select from 'react-select';
import { TextField } from "@material-ui/core";
import { useForm, Controller } from 'react-hook-form';

const options = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
  { value: 'vanilla', label: 'Vanilla' },
];

function App() {
  const { handleSubmit, control } = useForm();

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <Controller
        as={<Select options={options} />}
        control={control}
        rules={{ required: true }}
        onChange={([selected]) => {
          // React Select return object instead of value for selection
          return { value: selected };
        }}
        name="reactSelect"
      />

      <Controller
        as={<TextField />}
        name="firstName"
        control={control}
      />

      <button>submit</button>
    </form>
  );
}

包装您的受控组件并在其中收集数据的想法,同时仍然隔离在外部受控组件内重新渲染。

于 2019-12-31T05:16:34.450 回答
1

由于setValue@Domino987 在上面也解释了它的特性,对于那些用从服务器获取的数据填充表单的场景的替代方案是:

  • 用于useState保存获取的值;
  • ControllersdefaultValue设置值和;
  • 有条件地呈现的表单

一个伪例子:


const [state, setState] = useState({name: '', requested: false});

useEffect(() => {
    HTTP_Service.getName().then(name => {
      setCompanyInfo({name, requested: true})
    });

}, []);

const {name, requested} = state

return ({requested ? <Text>Loading...</Text> : <View>
    <Controller
        as={
        <Input               
          label={t('name')}
          placeholder={t('name')}
        />
        }
        defaultValue={name}
        control={control}
        name="name"
        onChange={args => args[0].nativeEvent.text}
    />
</View>});
于 2020-04-13T21:00:03.373 回答
0

react-hook-form 带有受控输入、是的验证、材质 UI 组件、setValue

    import React from 'react';
    import {useForm, Controller} from 'react-hook-form';
    import {yupResolver} from '@hookform/resolvers/yup';
    import Autocomplete from '@material-ui/lab/Autocomplete';
    import { TextField } from '@material-ui/core';
    import * as yup from 'yup';
    
    const schema = yup.object().shape({
      firstname: yup.string().required(),
      buyer: yup.string().required(),
    });
    
    const UserForm = () => {
      const {
        watch,
        setValue,
        register,
        handleSubmit,
        control,
        formState: {errors},
      } = useForm({
        defaultValues: {
          item: {"id":2,"name":"item2"},
        },
        resolver: yupResolver(schema),
      });
    
      const itemList = [
        {id: 1, name: 'item1'},
        {id: 2, name: 'item2'},
      ];
      return (
        <div
          style={{
            margin: '200px',
          }}>
          <form onSubmit={handleSubmit(d => console.table(d))}>
          
          
            <Controller
              control={control}
              name="item"
              rules={{required: true}}
              render={({field: {onChange, value}}) => (
                <Autocomplete
                  onChange={(event, item) => {
                    onChange(item);
                  }}
                  value={value}
                  options={itemList}
                  getOptionLabel={item => (item.name ? item.name : '')}
                  getOptionSelected={(option, value) =>
                    value === undefined || value === '' || option.id === value.id
                  }
                  renderInput={params => (
                    <TextField
                      {...params}
                      label="items"
                      margin="normal"
                      variant="outlined"
                      error={!!errors.item}
                      helperText={errors.item && 'item required'}
                      
                    />
                  )}
                />
              )}
            />
    
            <input type="submit" />
            <button
              onClick={() => {
              
                setValue('item', {id: 2, name: 'item2'});
              }}>
              setValue
            </button>
            <h6>data from register</h6>
            {<pre>{JSON.stringify(watch())}</pre>}
          </form>
        </div>
      );
    };
    
    export default UserForm;
于 2021-08-09T11:53:33.873 回答
0

就我而言,我setValue在模态中使用。它没有按预期工作。我不得不添加shouldUnregister: falseuseForm

const { errors, register, setValue, handleSubmit } = useForm({
resolver: useYupValidationResolver(CustomDomainSchema),
mode: 'all',
shouldUnregister: false,
});

我在阅读了这个讨论后解决了这个问题react-hook-form。这是一个关于沙盒的工作示例

于 2022-02-24T14:11:50.810 回答