Anyone experienced with this case, I don't know how to declare the Select properties in Typescript. Please help!
import React from 'react'
import Select, {components, IndicatorProps} from 'react-select'
import {connect} from 'react-redux'
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import { Users } from '../../../Redux/Users/UsersReducer';
import { RootState } from '../../../Redux/rootReducer';
interface SelectButtonProps {
onSelect: (event: React.FormEvent<HTMLSelectElement>) => void,
users: Users[],
stateId: string
}
const SelectUserButton:React.FunctionComponent<SelectButtonProps> = ({onSelect, users, stateId}): JSX.Element => {
const options = users.map( (user:Users) => ({label: user.name, value:`${user.id}`}))
const DropdownIndicator = (
props : IndicatorProps<any>
) => {
return (
<components.DropdownIndicator {...props}>
<ArrowDropDownIcon id="arrow_icon"/>
</components.DropdownIndicator>
);
};
const SingleValue = ({ children, ...props }:any) => (
<components.SingleValue {...props}>
{children}
</components.SingleValue>
);
return (
<div className='select__user'>
<label htmlFor='react-select-container'>Users</label>
<Select
SingleValue={SingleValue}
name="user"
components={{ DropdownIndicator }}
options={options}
onChange={onSelect}
maxMenuHeight={120}
placeholder={stateId}
/>
</div>
)
}
I got an error on the onChange event, because when using react-select, it will return an object.
And the browser also shows this error: "
The above error occurred in the <WithStyles(ForwardRef(SvgIcon))> component:
in WithStyles(ForwardRef(SvgIcon))
in ForwardRef
in ForwardRef (at SelectUserButton.tsx:23)
in div (created by Context.Consumer)
in EmotionCssPropInternal (created by DropdownIndicator)
in DropdownIndicator (at SelectUserButton.tsx:22)"
Let's start with the easy errors/issues which are to do with SingleValue
.
Your const SingleValue
is passing through all of the props it receives so it's not doing anything. You can write const SingleValue = components.SingleValue
and it will be the same thing. You can also pass components.SingleValue
directly without assigning it to a local variable.
I've had a look at the docs and source code for "react-select" and it doesn't seem like SingleValue
is a prop of Select
, though oddly this does not trigger a typescript error. Instead it should be an additional property on components
alongside DropdownIndicator
. It would be components={{ DropdownIndicator, SingleValue: components.SingleValue }}
, but since you aren't changing anything from the default, it's not necessary to include SingleValue
at all.
Now to the hard part which is the event handling.
Your interface declares that the onSelect
prop is a function which receives an event of type React.FormEvent<HTMLSelectElement>
. Unfortunately it is not possible to properly call this function because the "react-select" package doesn't pass the actual event to your callback functions.
If you want to keep using this package, you will need to change your SelectButtonProps
interface to something which is compatible with the data that you are getting back from the "react-select" onChange
function. For example, it can be a function which receives the selected Users
object:
interface SelectButtonProps {
onSelect: (user: Users) => void;
users: Users[];
stateId: string;
}
The typescript type of the first argument given to onChange
is any
, but in practice it is the type of each option in your options array which is {label: string, value: (the type of your user.id which I don't know if it's string or number) }
. Frankly, the package author could have done a better job there as they really should be giving you the correct type based on the options array that you are providing. There are multiple places that they should be using generics (value type, option type) where they are using vague types like any
instead.
This is a function which you can pass to onChange
:
const handleChange = (option: OptionTypeBase, meta: ActionMeta<any>): void => {
console.log({ option, meta });
onSelect({
name: option.label,
id: option.value
});
};
This is not necessary, but an alternative way of approaching this is that instead of mapping the users to a {label, value}
and then mapping that {label, value}
option back to a User
in your onChange
callback, what you can do is pass the users array directly to Select as options
. Then instead of using the default behaviors for getOptionLabel
( option => option.label
) and getOptionValue
( option => option.value
), you can pass your own mappings, which are user => user.name
and user => user.id
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.