无法在ReactJS TypeScript中向react-select的多选中添加onChange属性?

huangapple go评论74阅读模式
英文:

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 &#39;(selected: Vehicle[] | null) =&gt; void&#39; is not assignable to type &#39;(newValue: MultiValue&lt;Vehicle&gt;, actionMeta: ActionMeta&lt;Vehicle&gt;) =&gt; void&#39;.
  Types of parameters &#39;selected&#39; and &#39;newValue&#39; are incompatible.
    The type &#39;MultiValue&lt;Vehicle&gt;&#39; is &#39;readonly&#39; and cannot be assigned to the mutable type &#39;Vehicle[]&#39;.
    194 |                         isClearable={true}
    195 |                         backspaceRemovesValue={true}
  &gt; 196 |                         onChange={handleSelectChange}
        |                         ^^^^^^^^
    197 |                         
    198 |                     /&gt;

> Code I tried

    import Select from &#39;react-select&#39;;


    interface Vehicle {
       id: number;
       make: string;
       model: string;
       year: number;
   }

   const vehicles: Vehicle[] = [{
       id: 1,
       make: &#39;Ford&#39;,
       model: &#39;Fiesta&#39;,
       year: 2003,
   }, {
       id: 7,
       make: &#39;Audi&#39;,
       model: &#39;A4&#39;,
       year: 2009,
   }, ];

   const YourComponent: React.FC = () =&gt; {
       const [Vehicles, setVehicles] = useState &lt; Vehicle[] &gt; ([]);
       const handleSelectChange = (selected: Vehicle[] | null) =&gt; {
           if (selected) {
               setVehicles(selected);
           }
       };
       return (
                     &lt;Select
                        isMulti
                        getOptionLabel={(vehicle: Vehicle) =&gt; vehicle.model}
                        getOptionValue={(vehicle: Vehicle) =&gt; vehicle.model}
                        options={vehicles}
                        isClearable={true}
                        backspaceRemovesValue={true}
                        // onChange={handleSelectChange}     
                    /&gt;);
   };

   export default YourComponent;

答案1

得分: 1

react-select@^5.7.2

你有两种选择:

  1. 使用 OnChangeValue&lt;Option, true&gt;

让我们来看看这个类型:

export declare type SingleValue&lt;Option&gt; = Option | null;
export declare type MultiValue&lt;Option&gt; = readonly Option[];

// ...
export declare type OnChangeValue&lt;Option, IsMulti extends boolean&gt; = IsMulti extends true ? MultiValue&lt;Option&gt; : SingleValue&lt;Option&gt;;

它使用了 TS 条件类型,如果 isMultitrue,那么最终类型为 readonly Option[]

文档中提到:

IsMulti extends boolean = false
> 对于单选,此类型为 false,对于多选,此类型为 true。 对于导出的组件,默认为 false,因为 TypeScript 不够智能,无法确定如果未指定 isMulti prop,则应该为 false,但对于其他导出的接口,默认为布尔值,以处理单选和多选值。 此泛型主要用于确定传递给 onChange 的第一个参数的类型,如果 IsMultifalse,则为 Option | null,如果 IsMultitrue,则为 readonly Option[]

const YourComponent: React.FC = () =&gt; {
	const [Vehicles, setVehicles] = React.useState&lt;readonly Vehicle[]&gt;([]);
	const handleSelectChange = (selected: OnChangeValue&lt;Vehicle, true&gt;, actionMeta: ActionMeta&lt;Vehicle&gt;) =&gt; {
		console.log(selected, actionMeta);
		if (selected) {
			setVehicles(selected);
		}
	};
	return (
		&lt;Select
			isMulti
			getOptionLabel={(vehicle: Vehicle) =&gt; vehicle.model}
			getOptionValue={(vehicle: Vehicle) =&gt; vehicle.model}
			options={vehicles}
			isClearable={true}
			backspaceRemovesValue={true}
			onChange={handleSelectChange}
		/&gt;
	);
};

codesandbox

  1. 使用官方文档中提到的 read-only Option[]

此外,我们必须将 state 的类型声明为 readonly

const YourComponent: React.FC = () =&gt; {
    const [Vehicles, setVehicles] = React.useState&lt;readonly Vehicle[]&gt;([]);
    const handleSelectChange = (selected: readonly Vehicle[], actionMeta: ActionMeta&lt;Vehicle&gt;) =&gt; {
        console.log(selected, actionMeta);
        if (selected) {
            setVehicles(selected);
        }
    };
    return (
        &lt;Select
            isMulti
            getOptionLabel={(vehicle: Vehicle) =&gt; vehicle.model}
            getOptionValue={(vehicle: Vehicle) =&gt; vehicle.model}
            options={vehicles}
            isClearable={true}
            backspaceRemovesValue={true}
            onChange={handleSelectChange}
        /&gt;
    );
};

官方文档链接:official documentation

英文:

react-select@^5.7.2

You have two choices:

  1. Use OnChangeValue&lt;Option, true&gt;.

Let's check the this type:

export declare type SingleValue&lt;Option&gt; = Option | null;
export declare type MultiValue&lt;Option&gt; = readonly Option[];

//...
export declare type OnChangeValue&lt;Option, IsMulti extends boolean&gt; = IsMulti extends true ? MultiValue&lt;Option&gt; : SingleValue&lt;Option&gt;;

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 = () =&gt; {
	const [Vehicles, setVehicles] = React.useState&lt;readonly Vehicle[]&gt;([]);
	const handleSelectChange = (selected: OnChangeValue&lt;Vehicle, true&gt;, actionMeta: ActionMeta&lt;Vehicle&gt;) =&gt; {
		console.log(selected, actionMeta);
		if (selected) {
			setVehicles(selected);
		}
	};
	return (
		&lt;Select
			isMulti
			getOptionLabel={(vehicle: Vehicle) =&gt; vehicle.model}
			getOptionValue={(vehicle: Vehicle) =&gt; vehicle.model}
			options={vehicles}
			isClearable={true}
			backspaceRemovesValue={true}
			onChange={handleSelectChange}
		/&gt;
	);
};

codesandbox

  1. Use read-only Option[] mentioned at official documentation

Besides, we have to declare the type for state as readonly.

const YourComponent: React.FC = () =&gt; {
    const [Vehicles, setVehicles] = React.useState&lt;readonly Vehicle[]&gt;([]);
    const handleSelectChange = (selected: readonly Vehicle[], actionMeta: ActionMeta&lt;Vehicle&gt;) =&gt; {
        console.log(selected, actionMeta);
        if (selected) {
            setVehicles(selected);
        }
    };
    return (
        &lt;Select
            isMulti
            getOptionLabel={(vehicle: Vehicle) =&gt; vehicle.model}
            getOptionValue={(vehicle: Vehicle) =&gt; vehicle.model}
            options={vehicles}
            isClearable={true}
            backspaceRemovesValue={true}
            onChange={handleSelectChange}
        /&gt;
    );
};

huangapple
  • 本文由 发表于 2023年7月10日 13:30:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76650862.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定