英文:
unable to add onChange props in react-select's multi selection in ReactJS Typescript?
问题
在ReactJS中,我正在使用react-select来实现多选下拉字段,就像下面这样,但当我尝试添加onchange
属性时,我遇到了这个问题:
ERROR in src/components/Pages/CreatePage.tsx:196:25
TS2322: Type '(selected: Vehicle[] | null) => void' is not assignable to type '(newValue: MultiValue<Vehicle>, actionMeta: ActionMeta<Vehicle>) => void'.
Types of parameters 'selected' and 'newValue' are incompatible.
The type 'MultiValue<Vehicle>' is 'readonly' and cannot be assigned to the mutable type 'Vehicle[]'.
194 | isClearable={true}
195 | backspaceRemovesValue={true}
> 196 | onChange={handleSelectChange}
| ^^^^^^^^
197 |
198 | />
我尝试的代码:
import Select from 'react-select';
interface Vehicle {
id: number;
make: string;
model: string;
year: number;
}
const vehicles: Vehicle[] = [{
id: 1,
make: 'Ford',
model: 'Fiesta',
year: 2003,
}, {
id: 7,
make: 'Audi',
model: 'A4',
year: 2009,
}, ];
const YourComponent: React.FC = () => {
const [Vehicles, setVehicles] = useState < Vehicle[] > ([]);
const handleSelectChange = (selected: Vehicle[] | null) => {
if (selected) {
setVehicles(selected);
}
};
return (
<Select
isMulti
getOptionLabel={(vehicle: Vehicle) => vehicle.model}
getOptionValue={(vehicle: Vehicle) => vehicle.model}
options={vehicles}
isClearable={true}
backspaceRemovesValue={true}
// onChange={handleSelectChange}
/>
);
};
export default YourComponent;
英文:
In ReactJS, I'm using react-select to implement the multi-select dropdown field, like below but when I try to add onchange
props, I'm getting this issue
ERROR in src/components/Pages/CreatePage.tsx:196:25
TS2322: Type '(selected: Vehicle[] | null) => void' is not assignable to type '(newValue: MultiValue<Vehicle>, actionMeta: ActionMeta<Vehicle>) => void'.
Types of parameters 'selected' and 'newValue' are incompatible.
The type 'MultiValue<Vehicle>' is 'readonly' and cannot be assigned to the mutable type 'Vehicle[]'.
194 | isClearable={true}
195 | backspaceRemovesValue={true}
> 196 | onChange={handleSelectChange}
| ^^^^^^^^
197 |
198 | />
> Code I tried
import Select from 'react-select';
interface Vehicle {
id: number;
make: string;
model: string;
year: number;
}
const vehicles: Vehicle[] = [{
id: 1,
make: 'Ford',
model: 'Fiesta',
year: 2003,
}, {
id: 7,
make: 'Audi',
model: 'A4',
year: 2009,
}, ];
const YourComponent: React.FC = () => {
const [Vehicles, setVehicles] = useState < Vehicle[] > ([]);
const handleSelectChange = (selected: Vehicle[] | null) => {
if (selected) {
setVehicles(selected);
}
};
return (
<Select
isMulti
getOptionLabel={(vehicle: Vehicle) => vehicle.model}
getOptionValue={(vehicle: Vehicle) => vehicle.model}
options={vehicles}
isClearable={true}
backspaceRemovesValue={true}
// onChange={handleSelectChange}
/>);
};
export default YourComponent;
答案1
得分: 1
react-select@^5.7.2
你有两种选择:
- 使用
OnChangeValue<Option, true>
。
让我们来看看这个类型:
export declare type SingleValue<Option> = Option | null;
export declare type MultiValue<Option> = readonly Option[];
// ...
export declare type OnChangeValue<Option, IsMulti extends boolean> = IsMulti extends true ? MultiValue<Option> : SingleValue<Option>;
它使用了 TS 条件类型,如果 isMulti
为 true
,那么最终类型为 readonly Option[]
。
文档中提到:
IsMulti extends boolean = false
> 对于单选,此类型为 false
,对于多选,此类型为 true
。 对于导出的组件,默认为 false
,因为 TypeScript 不够智能,无法确定如果未指定 isMulti
prop,则应该为 false
,但对于其他导出的接口,默认为布尔值,以处理单选和多选值。 此泛型主要用于确定传递给 onChange
的第一个参数的类型,如果 IsMulti
为 false
,则为 Option | null
,如果 IsMulti
为 true
,则为 readonly Option[]
。
const YourComponent: React.FC = () => {
const [Vehicles, setVehicles] = React.useState<readonly Vehicle[]>([]);
const handleSelectChange = (selected: OnChangeValue<Vehicle, true>, actionMeta: ActionMeta<Vehicle>) => {
console.log(selected, actionMeta);
if (selected) {
setVehicles(selected);
}
};
return (
<Select
isMulti
getOptionLabel={(vehicle: Vehicle) => vehicle.model}
getOptionValue={(vehicle: Vehicle) => vehicle.model}
options={vehicles}
isClearable={true}
backspaceRemovesValue={true}
onChange={handleSelectChange}
/>
);
};
- 使用官方文档中提到的
read-only Option[]
。
此外,我们必须将 state
的类型声明为 readonly
。
const YourComponent: React.FC = () => {
const [Vehicles, setVehicles] = React.useState<readonly Vehicle[]>([]);
const handleSelectChange = (selected: readonly Vehicle[], actionMeta: ActionMeta<Vehicle>) => {
console.log(selected, actionMeta);
if (selected) {
setVehicles(selected);
}
};
return (
<Select
isMulti
getOptionLabel={(vehicle: Vehicle) => vehicle.model}
getOptionValue={(vehicle: Vehicle) => vehicle.model}
options={vehicles}
isClearable={true}
backspaceRemovesValue={true}
onChange={handleSelectChange}
/>
);
};
官方文档链接:official documentation
英文:
react-select@^5.7.2
You have two choices:
- Use
OnChangeValue<Option, true>
.
Let's check the this type:
export declare type SingleValue<Option> = Option | null;
export declare type MultiValue<Option> = readonly Option[];
//...
export declare type OnChangeValue<Option, IsMulti extends boolean> = IsMulti extends true ? MultiValue<Option> : SingleValue<Option>;
It uses TS conditional type, if isMulti
is true
, then the final type is readonly Option[]
.
This mentioned at documentation:
IsMulti extends boolean = false
> This type is false
for single-selects and is true
for multi-selects. It defaults to false for the exported components because TypeScript isn't smart enough to figure out that it should be false if the isMulti
prop is not specified, but on other exported interfaces it defaults to boolean so that it handles both single-select and multi-select values. This generic is primarily used to determine the type of the first argument passed to onChange which will be Option | null
if IsMulti
is false
and will be readonly Option[]
if IsMulti
is true
.
const YourComponent: React.FC = () => {
const [Vehicles, setVehicles] = React.useState<readonly Vehicle[]>([]);
const handleSelectChange = (selected: OnChangeValue<Vehicle, true>, actionMeta: ActionMeta<Vehicle>) => {
console.log(selected, actionMeta);
if (selected) {
setVehicles(selected);
}
};
return (
<Select
isMulti
getOptionLabel={(vehicle: Vehicle) => vehicle.model}
getOptionValue={(vehicle: Vehicle) => vehicle.model}
options={vehicles}
isClearable={true}
backspaceRemovesValue={true}
onChange={handleSelectChange}
/>
);
};
- Use
read-only Option[]
mentioned at official documentation
Besides, we have to declare the type for state
as readonly.
const YourComponent: React.FC = () => {
const [Vehicles, setVehicles] = React.useState<readonly Vehicle[]>([]);
const handleSelectChange = (selected: readonly Vehicle[], actionMeta: ActionMeta<Vehicle>) => {
console.log(selected, actionMeta);
if (selected) {
setVehicles(selected);
}
};
return (
<Select
isMulti
getOptionLabel={(vehicle: Vehicle) => vehicle.model}
getOptionValue={(vehicle: Vehicle) => vehicle.model}
options={vehicles}
isClearable={true}
backspaceRemovesValue={true}
onChange={handleSelectChange}
/>
);
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论