4

我正在使用 Material UI 的自动完成功能构建一个表单,并使用反冲进行状态管理。我也在使用 react-hook-form。我需要满足以下条件:

  1. 需要预先输入,允许输入的第一个字母从 API 返回选项列表以显示在自动完成中。每个字母将返回一个不同的选项列表以供选择。
  2. 还需要允许 freeSolo 以便用户可以手动输入值
  3. 需要被要求并遵循模式来验证表单。

我正在使用 react-hook-form<Controller>来控制输入并允许验证等功能,在帮助文本中显示错误消息等。

问题:我在根据我输入的内容过滤掉选项以及允许 freeSolo 时遇到问题。当我输入一个新值时,选项列表不会过滤。弹出窗口保持打开状态。我还需要验证模式验证的输入更改。我已经尝试使用以下示例onInputChange来使用 react-hook-formuseFormsetValue手动设置字段的值并验证表单。( {shouldValidate: true})。下面的示例是我为自动完成创建的自定义、可重用组件,以及在其他父组件中使用该自定义组件。我希望我包含尽可能多的细节,但如果没有,如果您需要更多信息,请告诉我。任何帮助将不胜感激!

父组件:

  const setTrainType = useSetRecoilState(TrainType)
  // Trains would return a list of trains based on letter of train type that was passed from input
  const trainsList = useRecoilValue(Trains)
  const trainOptions = useMemo(() => trainsList.map(trainIDFormatted), [
    trainsList,
  ])

const handleInputChange = useCallback(
    (_e: unknown, option: string, reason: string) => {
      const capitalized =
        option === capitalize(option) ? option : capitalize(option)
      setValue('trainID', capitalized, {shouldValidate: true})
      if (['input', 'reset'].includes(reason) && capitalized !== '') {
        setTrainType(capitalized.charAt(0))
      } else {
        setTrainType(undefined)
      }
    },
    [setTrainType, setValue],
  )

<Autocomplete
                autoSelect
                freeSolo
                disabled={disabled}
                helperText=" "
                label="Select a train"
                name="trainID"
                options={trainOptions}
                rules={{
                  pattern: {
                    message: 'Must match train ID pattern',
                    value: /^(?:[A-Z]-?[A-Z ]{6}-?[0-9 ]-?[0-9 ]{2}[A-Z ])?$/,
                  },
                  required: 'Train is required',
                }}
                onInputChange={handleInputChange}
              />

自定义自动完成组件:

import {
  AutocompleteProps,
  Autocomplete as MuiAutocomplete,
} from '@material-ui/lab'
import {get} from 'lodash'
import React, {ReactNode, useCallback} from 'react'
import {
  Controller,
  ControllerProps,
  FieldError,
  useFormContext,
} from 'react-hook-form'
import {useRenderInput} from './hooks'

interface Props
  extends Pick<ControllerProps<'select'>, 'rules'>,
    Omit<
      AutocompleteProps<string, false, false, true>,
      'error' | 'onChange' | 'required' | 'renderInput'
    > {
  helperText?: ReactNode
  label?: string
  name: string
}

/**
 * Render controlled autocomplete. Use react-form-hook's FormProvider.
 * @param props Component properties
 * @param props.helperText Default helper text for error
 * @param props.label Input label
 * @param props.name Name identifier for react-hook-form
 * @param props.required If true then item is required
 * @param props.rules Select rules
 * @return React component
 */
export const Autocomplete = ({
  helperText,
  label,
  name,
  rules,
  ...props
}: Props) => {
  // eslint-disable-next-line @typescript-eslint/unbound-method
  const {control, errors, watch} = useFormContext()
  const error: FieldError | undefined = get(errors, name)
  const required = get(rules, 'required') !== undefined
  const value = watch(name)
  const renderAutocompleteInput = useRenderInput({
    error: error !== undefined,
    helperText: get(error, 'message', helperText),
    label,
    required,
  })
  const handleOnChange = useCallback(
    (_e: unknown, option: string | null) => option,
    [],
  )
  const renderAutocomplete = useCallback(
    params => (
      <MuiAutocomplete
        {...props}
        {...params}
        renderInput={renderAutocompleteInput}
        onChange={handleOnChange}
      />
    ),
    [handleOnChange, props, renderAutocompleteInput],
  )

  return (
    <Controller
      control={control}
      defaultValue={value ?? ''}
      name={name}
      render={renderAutocomplete}
      rules={rules}
    />
  )
}

它看起来像什么:

在此处输入图像描述

4

0 回答 0