【问题标题】:How to use MUI Select with react-hook-form?如何将 MUI Select 与 react-hook-form 一起使用?
【发布时间】:2020-11-23 23:07:38
【问题描述】:

我使用 MUI 和 React Hook Form 在 React 中构建了一个表单。我正在尝试创建一个自定义 TextField 元素,该元素可用作 Select Input。我希望它是一个带有 Ref 道具的不受控制的组件。我尝试按照 MUI 和 React Hook Form 文档的建议传递 inputRef 道具,但没有成功。

            <TextField
              id="id"
              name="name"
              select
              native="true"
              className={classes.textField}
              label="label"
              margin="normal"
              variant="outlined"
              inputRef={register({ required: "Choose one option" })}
              error={!!errors.name}
            >
              <MenuItem value="">Choose one option</MenuItem>
              <MenuItem value="3">03</MenuItem>
              <MenuItem value="6">06</MenuItem>
              <MenuItem value="9">09</MenuItem>
              <MenuItem value="12">12</MenuItem>
              <MenuItem value="16">16</MenuItem>
              <MenuItem value="18">18</MenuItem>
            </TextField>

我发现的一件事是,如果我将原生 selectref 一起使用,效果很好。

此外,我尝试将 inputRef 属性更改为 SelectProps 属性,但也没有用。

【问题讨论】:

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


【解决方案1】:

使用带有 React hook 形式的 Material-ui 中的 Select 组件需要您使用 Controller https://react-hook-form.com/api#Controller 实现自定义逻辑

这是一个可重用的组件,有望简化代码以在您的应用中使用该 Select 组件:

import FormControl from "@material-ui/core/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import Select from "@material-ui/core/Select";
import { Controller } from "react-hook-form";

const ReactHookFormSelect = ({
  name,
  label,
  control,
  defaultValue,
  children,
  ...props
}) => {
  const labelId = `${name}-label`;
  return (
    <FormControl {...props}>
      <InputLabel id={labelId}>{label}</InputLabel>
      <Controller
        as={
          <Select labelId={labelId} label={label}>
            {children}
          </Select>
        }
        name={name}
        control={control}
        defaultValue={defaultValue}
      />
    </FormControl>
  );
};
export default ReactHookFormSelect;

您可以像这样在您的应用中使用它:

           <ReactHookFormSelect
              id="numero_prestacao"
              name="numero_prestacao"
              className={classes.textField}
              label="Em quantas parcelas?"
              control={control}
              defaultValue={numero_prestacao || ""}
              variant="outlined"
              margin="normal"
            >
              <MenuItem value="">Escolha uma opção</MenuItem>
              <MenuItem value="3">03 parcelas</MenuItem>
              <MenuItem value="6">06 parcelas</MenuItem>
              <MenuItem value="9">09 parcelas</MenuItem>
              <MenuItem value="12">12 parcelas</MenuItem>
              <MenuItem value="16">16 parcelas</MenuItem>
              <MenuItem value="18">18 parcelas</MenuItem>
            </ReactHookFormSelect>

这里是您的 codeSandBox 更新了这个组件用于信息表单中的选择:

https://codesandbox.io/s/unit-multi-step-form-kgic4?file=/src/Register/Information.jsx:4406-5238

【讨论】:

  • 如何处理 onChange 事件?
  • 在这种情况下,我们没有 onChange bc 输入由 DOM 处理,即不受控制的组件。
  • 是的,正如@YungHK 所说,react-hook-form 使用不受控制的输入。如果您需要表单中输入的值,可以使用 watch:react-hook-form.com/api#watch
  • 为避免以下错误,您需要确保传递一个有效的默认值:Material-UI: A component is changing the uncontrolled value state of Select to be controlled. Elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled Select element for the lifetime of the component.
  • 是的 Paku 可以使用有效的默认值谢谢大家
【解决方案2】:

这是我的代码,希望它可以帮助,需要使用setValue

  <TextField
    fullWidth
    inputRef={register({
      name: 'name',
    })}
    select
    onChange={e => setValue('name', e.target.value, true)}
    label={label}
    defaultValue={defaultValue}
  >
    {options.map((option) => (
      <MenuItem key={option.label} value={option.value}>
        {option.label}
      </MenuItem>
    ))}
  </TextField>

这里使用native select,不需要setValue,但value总是字符串

<TextField
    fullWidth
    select
    SelectProps={{
      native: true,
      inputProps: { ref: register, name: 'name' }
    }}
    label={label}
    defaultValue={defaultValue}
  >
    {options.map((option) => (
      <option key={option.label} value={option.value}>
        {option.label}
      </option>
    ))}
  </TextField>

【讨论】:

    【解决方案3】:

    RHF v7 更新

    以下是 RHF 形式的 MUI Select 的最小代码示例:

    const { formState, getValues, watch, register, handleSubmit } = useForm();
    const { errors } = formState;
    
    <TextField
      select
      fullWidth
      label="Select"
      defaultValue=''
      inputProps={register('currency', {
        required: 'Please enter currency',
      })}
      error={errors.currency}
      helperText={errors.currency?.message}
    >
      {currencies.map((option) => (
        <MenuItem key={option.value} value={option.value}>
          {option.label}
        </MenuItem>
      ))}
    </TextField>
    

    【讨论】:

    • 你的演示有错误A component is changing an uncontrolled input to be controlled
    • @Randall 这是来自 MUI 的可怕警告,因为 RHF 默认使用不受控模式,在不受控模式下,value 未定义,defaultValue 是可选的,但在此 MUI 组件中,您需要出于某种原因明确提供一个。无论如何我修正了我的答案,它现在应该可以正常工作了。
    【解决方案4】:

    ✔ 我遇到了同样的问题,这就是我解决我的问题的方法:

    <Select ... onChange={e => register({ name: 'academicLevel', value: e.target.value })}/>
    

    more info

    【讨论】:

      【解决方案5】:

      这是一个使用带有 React 钩子形式的 Material-UI 的示例。您需要在 TextField 的 'inputRef' 属性中添加验证。您还需要添加“onChange”功能以保持状态更新。 'shouldValidate' 将触发验证。

        <TextField
          select
          name='city'
          inputRef={register({ required: true })}
          onChange={e => setValue('city', e.target.value, { shouldValidate: true })}
          label="City"
          defaultValue="">
          {cityList.map((option, index) => (
            <MenuItem key={index} value={option}>
              {option}
            </MenuItem>
          ))}
        </TextField>
      
        {errors.city && <ErrorText>City is required</ErrorText>}
      

      【讨论】:

        【解决方案6】:

        当您使用带有材质 UI 的 react-hook-form 时,您不需要使用 onChange 和 setState。仅使用 inputRef 即可!

        【讨论】:

        • 问题是关于使用选择
        【解决方案7】:

        只需要将寄存器传递给Input Ref

         <Select
           variant="outlined"
           name="reason"
           inputRef={register({ required: true })}
          >
        

        【讨论】:

          猜你喜欢
          • 2022-10-13
          • 1970-01-01
          • 2020-09-24
          • 1970-01-01
          • 2022-11-22
          • 2021-05-28
          • 2022-06-12
          • 1970-01-01
          • 2020-04-04
          相关资源
          最近更新 更多