如何将 MUI Select 与 react-hook-form 一起使用?

Posted

技术标签:

【中文标题】如何将 MUI Select 与 react-hook-form 一起使用?【英文标题】:How to use MUI Select with 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 属性,但也没有用。

【问题讨论】:

看看Controller:react-hook-form.com/api#Controller 【参考方案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 )
  >

【讨论】:

以上是关于如何将 MUI Select 与 react-hook-form 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

H5+和mui开发的app,拍照完成后如何将拍到的照片在页面中形成预览图

如何使用 mui-datatable 实现 aws 订阅

MUI - 如何将组件对齐到中心/右侧?

[MUI专题] 优化标题栏

[MUI专题] 登录页面的美化

如何将图标添加到 MUI 数据表的标题