在Material-UI自动完成中使用react-hook-form控制器的正确方法

时间:2020-05-07 10:10:47

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

我正在尝试使用自定义的Material-UI Autocomplete组件并将其连接到react-hook-form

TLDR:需要在没有defaultValue的情况下将MUI自动完成与react-hook-form控制器一起使用

我的自定义Autocomplete组件采用结构为{_id:'', name: ''}的对象,它显示名称并在选择选项时返回_idAutocomplete可以正常工作。

<Autocomplete
  options={options}
  getOptionLabel={option => option.name}
  getOptionSelected={(option, value) => option._id === value._id}
  onChange={(event, newValue, reason) => {
    handler(name, reason === 'clear' ? null : newValue._id);
  }}
  renderInput={params => <TextField {...params} {...inputProps} />}
/>

为了使其与react-hook-form一起使用,我在setValues中将onChange设置为Autocomplete的处理程序,并在{ {1}}如下

useEffect

这很好用,但是我不希望使用useEffect(() => { register({ name: "country1" }); },[]); 钩子,而直接以某种方式使用寄存器。

接下来,我尝试使用useEffect中的Controller组件来正确注册表单中的字段,而不使用react-hook-form钩子

useEffect

我已经更改了<Controller name="country2" as={ <Autocomplete options={options} getOptionLabel={option => option.name} getOptionSelected={(option, value) => option._id === value._id} onChange={(event, newValue, reason) => reason === "clear" ? null : newValue._id } renderInput={params => ( <TextField {...params} label="Country" /> )} /> } control={control} /> 组件中的onChange以直接返回该值,但是它似乎不起作用。

Autocomplete上使用inputRef={register}不会对我有用,因为我要保存<TextField/>而不是_id

HERE是具有这两种情况的有效沙箱。第一个在name中具有useEffectsetValue的作品。我第二次尝试使用Autocomplete组件

感谢您的帮助。

LE

在Bill通过MUI自动完成功能的工作沙箱发表评论后,我设法获得了有效的结果

Controller

唯一的问题是我在控制台中得到了<Controller name="country" as={ <Autocomplete options={options} getOptionLabel={option => option.name} getOptionSelected={(option, value) => option._id === value._id} renderInput={params => <TextField {...params} label="Country" />} /> } onChange={([, { _id }]) => _id} control={control} />

Material-UI:某个组件正在更改要控制的自动完成的不受控制的值状态。

我尝试为其设置一个MUI Error,但它的行为仍然如此。另外,由于不需要表单中的这些字段,因此我也不想从options数组中设置默认值。

更新后的沙盒HERE

仍然非常感谢任何帮助

3 个答案:

答案 0 :(得分:5)

所以,我解决了这个问题。但这揭示了我认为是自动完成功能中的错误。

首先...专门针对您的问题,您可以通过向MUI Error添加 defaultValue 来消除<Controller>。但这仅仅是另一轮或问题的开始。

问题是getOptionLabelgetOptionSelectedonChange的函数有时会传递值(在这种情况下为_id),有时会传递选项结构-正如您所期望的。

这是我最后想出的代码:

import React from "react";
import { useForm, Controller } from "react-hook-form";
import { TextField } from "@material-ui/core";
import { Autocomplete } from "@material-ui/lab";
import { Button } from "@material-ui/core";
export default function FormTwo({ options }) {
  const { register, handleSubmit, control } = useForm();

  const getOpObj = option => {
    if (!option._id) option = options.find(op => op._id === option);
    return option;
  };

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <Controller
        name="country"
        as={
          <Autocomplete
            options={options}
            getOptionLabel={option => getOpObj(option).name}
            getOptionSelected={(option, value) => {
              return option._id === getOpObj(value)._id;
            }}
            renderInput={params => <TextField {...params} label="Country" />}
          />
        }
        onChange={([, obj]) => getOpObj(obj)._id}
        control={control}
        defaultValue={options[0]}
      />
      <Button type="submit">Submit</Button>
    </form>
  );
}

答案 1 :(得分:4)

接受的答案(可能)适用于错误版本的自动完成。我认为此错误已在一段时间后修复,因此可以稍微简化解决方案。

当使用react-hook-form和material-ui:https://codesandbox.io/s/react-hook-form-controller-601-j2df5

时,这是非常有用的参考/代码框。

在上面的链接中,我修改了自动完成示例:

import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';


const ControlledAutocomplete = ({ options = [], renderInput, getOptionLabel, onChange: ignored, control, defaultValue, name, renderOption }) => {
  return (
    <Controller
      render={({ onChange, ...props }) => (
        <Autocomplete
          options={options}
          getOptionLabel={getOptionLabel}
          renderOption={renderOption}
          renderInput={renderInput}
          onChange={(e, data) => onChange(data)}
          {...props}
        />
      )}
      onChange={([, data]) => data}
      defaultValue={defaultValue}
      name={name}
      control={control}
    />
  );
}

用法:

<ControlledAutocomplete
    control={control}
    name="inputName"
    options={[{ name: 'test' }]}
    getOptionLabel={(option) => `Option: ${option.name}`}
    renderInput={(params) => <TextField {...params} label="My label" margin="normal" />}
    defaultValue={null}
/>

control来自useForm(}的返回值

请注意,我将null传递为defaultValue,因为在我的情况下,此输入不是必需的。如果您离开defaultValue,可能会从material-ui库中得到一些错误。

答案 2 :(得分:-1)

不使用控制器,借助 register、useForm 的 setValue 和 value、Autocomplete 的 onChange 可以达到相同的效果。

const [selectedCaste, setSelectedCaste] = useState([]);
const {register, errors, setValue} = useForm();

useEffect(() => {
  register("caste");
}, [register]);

return (
                <Autocomplete
                  multiple
                  options={casteList}
                  disableCloseOnSelect
                  value={selectedCaste}
                  onChange={(_, values) => {
                    setSelectedCaste([...values]);
                    setValue("caste", [...values]);
                  }}
                  getOptionLabel={(option) => option}
                  renderOption={(option, { selected }) => (
                    <React.Fragment>
                      <Checkbox
                        icon={icon}
                        checkedIcon={checkedIcon}
                        style={{ marginRight: 8 }}
                        checked={selected}
                      />
                      {option}
                    </React.Fragment>
                  )}
                  style={{ width: "100%" }}
                  renderInput={(params) => (
                    <TextField
                      {...params}
                      id="caste"
                      error={!!errors.caste}
                      helperText={errors.caste?.message}
                      variant="outlined"
                      label="Select caste"
                      placeholder="Caste"
                    />
                  )}
                />
);