封装MUI TypeScript Autocomplete组件以返回指定属性标量值
封装MUI Autocomplete:将值映射为对象指定属性类型
需求场景
MUI Autocomplete默认绑定的value和onChange参数类型是其options数组中对象的完整类型。但实际业务中,表单往往只需要提交对象的某个标量属性(比如id),而非整个对象。我们需要封装一个组件,让value和onChange的参数直接对应到指定属性的类型,同时兼容multiple属性(开启时value变为该标量的数组类型)。
组件实现
import React, { useCallback } from 'react'; import Autocomplete, { AutocompleteProps } from '@mui/material/Autocomplete'; type WrappedAutocompleteProps< T extends object, K extends keyof T, Multiple extends boolean = false > = Omit<AutocompleteProps<T, Multiple>, 'value' | 'onChange'> & { valueProp: K; value: Multiple extends true ? T[K][] : T[K] | null; onChange: (value: Multiple extends true ? T[K][] : T[K] | null) => void; }; export const WrappedAutocomplete = < T extends object, K extends keyof T, Multiple extends boolean = false >({ valueProp, value, onChange, options, multiple, ...rest }: WrappedAutocompleteProps<T, K, Multiple>) => { // 把外部传入的标量值转换为Autocomplete需要的对象 const internalValue = useCallback(() => { if (multiple) { return (value as T[K][])?.map(id => options.find(opt => opt[valueProp] === id)).filter(Boolean); } return options.find(opt => opt[valueProp] === value); }, [value, options, valueProp, multiple]); // 把Autocomplete返回的对象转换为外部需要的标量值 const internalOnChange = useCallback( (_event: React.SyntheticEvent, newValue: Multiple extends true ? T[] : T | null) => { if (multiple) { onChange((newValue as T[])?.map(item => item[valueProp]) ?? []); } else { onChange(newValue ? newValue[valueProp] : null); } }, [onChange, valueProp, multiple] ); return ( <Autocomplete {...rest} multiple={multiple} options={options} value={internalValue()} onChange={internalOnChange} /> ); };
使用示例
import { useState, useCallback } from 'react'; import { WrappedAutocomplete } from './WrappedAutocomplete'; // 定义选项对象类型 interface Film { id: number; label: string; } // 示例选项数组 const top100Films: Film[] = [ { id: 1, label: 'The Shawshank Redemption' }, { id: 2, label: 'The Godfather' }, // ...其他影片 ]; // 单选场景 const Demo = () => { const [value, setValue] = useState<number | null>(null); const handleChange = useCallback((selectedId: number | null) => { setValue(selectedId); // 直接拿到id用于表单提交 console.log('选中的影片ID:', selectedId); }, []); return ( <WrappedAutocomplete<Film, 'id'> valueProp="id" options={top100Films} value={value} onChange={handleChange} renderInput={(params) => <input {...params} placeholder="选择影片" />} /> ); }; // 多选场景 const MultiDemo = () => { const [values, setValues] = useState<number[]>([]); const handleChange = useCallback((selectedIds: number[]) => { setValues(selectedIds); console.log('选中的影片ID列表:', selectedIds); }, []); return ( <WrappedAutocomplete<Film, 'id', true> valueProp="id" multiple={true} options={top100Films} value={values} onChange={handleChange} renderInput={(params) => <input {...params} placeholder="多选影片" />} /> ); };
关键说明
- 泛型
T对应选项对象的类型,K对应要提取的属性键,Multiple标记是否开启多选 internalValue负责将外部传入的标量值(或数组)转换为Autocomplete需要的对象(或对象数组)internalOnChange负责将Autocomplete返回的对象(或对象数组)转换为外部需要的标量值(或数组)- 完全兼容MUI Autocomplete的原生属性,只需额外传入
valueProp指定映射属性
内容的提问来源于stack exchange,提问作者Jordan Lewallen
相关产品推荐
相关产品推荐

