javascript - 自動建議 renderInputComponent - inputProps 屬性 'onChange' 的類型不相容
當我在使用帶有自訂輸入 styled-component 的 react-autosuggest 時,我遇到了這個 Typescript 錯誤。
屬性 'onChange' 的類型不相容。類型 '(event: FormEvent, params: ChangeEvent) => void' 無法賦值給類型 '(event: ChangeEvent) => void'。
程式碼:(注意這不是完整的,只是相關部分)
// styled.ts
export const Input = styled.input`
// styles
`;
// index.tsx
function renderInput(
inputProps: Autosuggest.InputProps<SuggestionSearch>,
placeholder: string
) {
// --> error here
return <Input {...inputProps} placeholder={placeholder} />;
}
const MyComponent = () => {
const autosuggestRef = React.useRef<
Autosuggest<SuggestionSearch, SuggestionSearch>
>(null);
const onChange = (event: React.FormEvent, { newValue }: ChangeEvent) =>
setValue(newValue);
const inputProps = {
value,
onChange,
onKeyPress: onEnterPress,
};
return (
<Autosuggest
ref={autosuggestRef}
renderInputComponent={props => renderInput(props, placeholder)}
inputProps={inputProps}
// other props
/>
)
}
不確定如何解決這個問題,因為自動建議的 onChange 函數會覆蓋基本輸入的 onChange 屬性。
答案#1
我幾乎整晚都在自己處理這個問題。看起來這是一個錯誤。這是 InputProps 的簽名:
interface InputProps<TSuggestion>
extends Omit<React.InputHTMLAttributes<any>, 'onChange' | 'onBlur'> {
onChange(event: React.FormEvent<any>, params: ChangeEvent): void;
onBlur?(event: React.FocusEvent<any>, params?: BlurEvent<TSuggestion>): void;
value: string;
}
看起來我們需要自己建立一個 Input 元件,它能接受這種類型的 onChange 簽名,或者將這個 onChange 包裝在標準的 onChange 中。
所以,這是我的做法:
const renderInputComponent = (inputProps: InputProps<TSuggestion>): React.ReactNode => {
const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>): void => {
inputProps.onChange(event, { newValue: event.target.value, method: 'type' });
};
return <Input {...inputProps} onChange={onChangeHandler} />;
}
兩個潛在的錯誤:
- 請注意,返回的
event是React.ChangeEvent而不是React.FormEvent。這是小差異,但如果你實際使用它並且對事件特別在意,可能會在執行時造成問題。 - 返回的
params: ChangeEvent僅包含type事件方法。如果你需要其他的,比如 click、esc 等,你必須自行補充(例如透過onKeyUp,然後再調用 `onChange(...{method: 'esc'})
根據文件:
注意:使用 renderInputComponent 時,您仍然需要指定通常的 inputProps。Autosuggest 會將您提供的 inputProps 與其他為了可及性所需的屬性(例如 'aria-activedescendant')合併,並將合併後的 inputProps 傳遞給 renderInputComponent。
你不必這樣做:
renderInputComponent={props => renderInput(props, placeholder)}
只需將 placeholder 直接傳入你的 inputProps,它就會在 renderInputComponent 中直接回傳給你。
const inputProps = {
value,
onChange,
onKeyPress: onEnterPress,
placeholder: 'something!`
};
答案#2
我的問題是 renderInputComponent 上的 onChange() 並不會觸發 onSuggestionsFetchRequested。
如果我不使用自訂輸入(透過 renderInputComponent),那麼一切都運作正常——onSuggestionsFetchRequested 會被觸發,建議列表會顯示。
主要成分:
const MySearchBox: FC<MySearchBoxProps> = (props) => {
// Autosuggest will pass through all these props to the input.
const inputProps = {
placeholder: props.placeholder,
value: props.value,
onChange: props.onChange
};
return (
<Autosuggest
suggestions={props.suggestions}
onSuggestionsFetchRequested={props.onSuggestionsFetechRequested}
onSuggestionsClearRequested={props.onSuggestionsClearRequested}
getSuggestionValue={props.getSuggestionValue}
shouldRenderSuggestions={(value) => value.trim().length > 2}
renderSuggestion={(item: ISuggestion) => {
<div className={classes.suggestionsList}>{`${item.text} (${item.id})`}</div>;
}}
renderInputComponent={(ip: InputProps<ISuggestion>) => {
const params: InputProps<ISuggestion> = {
...ip,
onChange: props.onChange
};
return renderInput(params);
}}
inputProps={inputProps}
/>
);
};
export { MySearchBox };
自訂輸入元件:
import React, { FC, ChangeEvent } from 'react';
import SearchIcon from '@material-ui/icons/Search';
import useStyles from './searchInput.styles';
import { Input } from '@material-ui/core';
type SearchInputBoxProps = {
loading?: boolean;
searchIconName: string;
minWidth?: number;
placeHolder?: string;
onChange?: (e: ChangeEvent, params: { newValue: string; method: string }) => void;
};
const SearchInputBox: FC<SearchInputBoxProps> = (props) => {
const classes = useStyles();
return (
<div className={classes.root}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<Input
placeholder={props.placeHolder}
classes={{
root: classes.inputContainer,
input: classes.inputBox
}}
inputProps={{ 'aria-label': 'search' }}
onChange={(e) => {
const params: { newValue: string; method: string } = {
newValue: e.target.value,
method: 'type'
};
console.log(`e: ${JSON.stringify(params)}`);
if (props.onChange) props.onChange(e, params);
}}
//onMouseOut={(e) => alert(e.currentTarget.innerText)}
/>
</div>
);
};
export { SearchInputBox };
渲染函數:
const renderInput = (inputProps: InputProps<ISuggestion>): React.ReactNode => {
return <SearchInputBox loading={false} onChange={inputProps.onChange} placeHolder={inputProps.placeholder} searchIconName={'search'} {...inputProps.others} />;
};
