I am creating a custom MultiValueRemove component for my react-select Select input. I would like to pass additional properties into my custom component; however, I don't see an easy way to do that without going against react-select's rules on inline declaration.
My code currently looks like this (forked from the default MultiValueRemove example):
import React, { useState } from "react";
import EmojiIcon from "@atlaskit/icon/glyph/emoji";
import Select, { components, MultiValueRemoveProps } from "react-select";
import { ColourOption, colourOptions } from "./docs/data";
const CustomMultiValueRemove = (props: MultiValueRemoveProps<ColourOption>) => {
return (
<components.MultiValueRemove {...props}>
<EmojiIcon label="Emoji" primaryColor={colourOptions[2].color} />
</components.MultiValueRemove>
);
};
export default () => {
// I would like to track the number of times the remove icon has been clicked.
// How can I pass these into my custom MultiValueRemove component?
const [numberOfRemoveClicks, setNumberOfRemoveClicks] = useState(0);
return (
<Select
closeMenuOnSelect={false}
components={{ MultiValueRemove: CustomMultiValueRemove }}
defaultValue={[colourOptions[4], colourOptions[5]]}
isMulti
options={colourOptions}
/>
);
};
How can I pass numberOfRemoveClicks and setNumberOfRemoveClicks to MultiValueRemove?
One potential solution I see is to inline the call to the custom component, pass my custom properties there, and override innerProps as necessary. For example:
interface CustomMultiValueRemoveProps
extends MultiValueRemoveProps<ColourOption> {
numberOfRemoveClicks: number;
setNumberOfRemoveClicks: (value: number) => void;
}
const CustomMultiValueRemove = ({
numberOfRemoveClicks,
setNumberOfRemoveClicks,
innerProps,
...props
}: CustomMultiValueRemoveProps) => {
const newInnerProps = {
...innerProps,
onClick: (event: any) => {
setNumberOfRemoveClicks(numberOfRemoveClicks + 1);
innerProps.onClick(event);
}
};
return (
<components.MultiValueRemove innerProps={newInnerProps} {...props}>
<EmojiIcon label="Emoji" primaryColor={colourOptions[2].color} />
</components.MultiValueRemove>
);
};
export default () => {
const [numberOfRemoveClicks, setNumberOfRemoveClicks] = useState(0);
return (
<Select
...
components={{
// Pass properties in here
MultiValueRemove: (props) => {
return (
<CustomMultiValueRemove
numberOfRemoveClicks={numberOfRemoveClicks}
setNumberOfRemoveClicks={setNumberOfRemoveClicks}
{...props}
/>
);
}
}}
...
/>
);
};
The above solution works just fine; however, as I mentioned at the top of the question, this goes against react-select's rules on inline declaration so I'd like to avoid this approach if possible.
Here is a link to a code sandbox containing some example code I forked: https://codesandbox.io/s/codesandboxer-example-forked-93dtto?file=/example.tsx
Any advice would be greatly appreciated!
I think you should be able to do something like this
import React, { useState } from "react";
import EmojiIcon from "@atlaskit/icon/glyph/emoji";
import Select, { components, MultiValueRemoveProps } from "react-select";
import { ColourOption, colourOptions } from "./docs/data";
const CustomMultiValueRemove = (props: MultiValueRemoveProps<ColourOption>) => {
return (
<components.MultiValueRemove {...props}>
<EmojiIcon label="Emoji" primaryColor={colourOptions[2].color} />
</components.MultiValueRemove>
);
};
export default () => {
// I would like to track the number of times the remove icon has been clicked.
// How can I pass these into my custom MultiValueRemove component?
const [numberOfRemoveClicks, setNumberOfRemoveClicks] = useState(0);
// you can memoize this if needed
const renderCustomMultiValue = (props) => (
<CustomMultiValueRemove
numberOfRemoveClicks={numberOfRemoveClicks}
setNumberOfRemoveClicks={setNumberOfRemoveClicks}
{...props}
/>
)
return (
<Select
closeMenuOnSelect={false}
components={{ MultiValueRemove: renderCustomMultiValue }}
defaultValue={[colourOptions[4], colourOptions[5]]}
isMulti
options={colourOptions}
/>
);
};
The much more straightforward approach would be to add custom properties to Select and access them in the component via props.selectProps.<customPropertyName>.
Here is the source of the sample code below.
import Select, { components, GroupBase, SingleValueProps } from 'react-select';
declare module 'react-select/dist/declarations/src/Select' {
export interface Props<
Option,
IsMulti extends boolean,
Group extends GroupBase<Option>
> {
myCustomProp: string;
}
}
function SingleValue({
children,
...props
}: SingleValueProps<MyOption, false>) {
return (
<div>
<label htmlFor={props.selectProps.name}>
{props.selectProps.myCustomProp}
</label>
<components.SingleValue {...props}>{children}</components.SingleValue>
<div className="ml-1">
<components.DownChevron />
</div>
</div>
);
}
export default function App() {
return (
<Select<MyOption>
id={id}
options={options}
components={{ SingleValue }}
myCustomProp="foobar"
/>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With