我正在使用 Material UI 的自动完成功能构建一个表单,并使用反冲进行状态管理。我也在使用 react-hook-form。我需要满足以下条件:
- 需要预先输入,允许输入的第一个字母从 API 返回选项列表以显示在自动完成中。每个字母将返回一个不同的选项列表以供选择。
- 还需要允许 freeSolo 以便用户可以手动输入值
- 需要被要求并遵循模式来验证表单。
我正在使用 react-hook-form<Controller>
来控制输入并允许验证等功能,在帮助文本中显示错误消息等。
问题:我在根据我输入的内容过滤掉选项以及允许 freeSolo 时遇到问题。当我输入一个新值时,选项列表不会过滤。弹出窗口保持打开状态。我还需要验证模式验证的输入更改。我已经尝试使用以下示例onInputChange
来使用 react-hook-formuseForm
并setValue
手动设置字段的值并验证表单。( {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}
/>
)
}
它看起来像什么: