如果输入在材质ui对话框中,则react-hook-form的setValue方法不起作用

时间:2019-12-30 06:40:53

标签: reactjs material-ui react-hook-form

我试图使用react-hook-form来验证输入。但是我发现,如果将输入放置在Material UI的对话框组件中,则react-hook-form的setValue不能按预期工作,但是当我删除对话框组件时它可以工作。我想这是因为该值是在组件安装之前设置的,但仍然找不到解决方案。

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

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

我尝试使用useState来控制输入值,但是还有另一个问题。清除输入后,单击“提交”按钮,并显示错误消息,我输入的第一个字母将不会显示。

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

4 个答案:

答案 0 :(得分:1)

由于setValue具有其特殊性(如上@ Domino987所述),因此对于其中表单填充有从服务器获取的数据的方案,一种替代方案是:

  • 使用useState保留获取的值;
  • Controller的{​​{1}}来设置值和;
  • 有条件呈现的表单

一个伪示例:

defaultValue

答案 1 :(得分:0)

用于外部受控组件

如果您使用的是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>
  );
}

包裹受控组件并收集数据的想法仍然可以隔离外部受控组件内部的重新渲染。

答案 2 :(得分:0)

问题出在寄存器功能上。您将在调用Textfield的引用之后使用注册功能注册Textfield。

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

这就是为什么显示文本字段的值为“”的原因。您需要在调用render和ref回调之后调用setValue,以使该值保持不变。

您有两种选择可以做到这一点:

  1. 更改setTimeout后,在useEffect中使用异步延迟(open或promise)设置async值。因此,如果将open添加到useEffect依赖数组并设置值async,它将起作用。这是Sandbox
  2. 设置文本字段的默认值,或者使用useForm({defaultValues: {name: '123}})将默认值添加到钩子中。

答案 3 :(得分: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;