I have been upgrading from @material-ui/icons 4.11.2 to @mui/material and @mui/icons-material at 5.2.3
I realize that material UI is not directly used in react-select however as far as I can see there is some interaction.
The upgrade from Material UI Icons v4 to v5 seemed to be going fine. But then, I noticed all the react-select dropdowns explode the application (instant blank screen) with this error in the console:
TypeError: theme.transitions is undefined ./node_modules/@mui/material/SvgIcon/SvgIcon.js/SvgIconRoot< node_modules/@mui/material/SvgIcon/SvgIcon.js:49
46 | display: 'inline-block', 47 | fill: 'currentColor', 48 | flexShrink: 0, 49 | transition: theme.transitions.create('fill', { | ^ 50 | duration: theme.transitions.duration.shorter 51 | }), 52 | fontSize: {
I’ve been pouring over the Material UI v4 -> v5 migration guide, have upgraded our react and react-dom libraries to 17.0.2 and react-select library to 5.2.1, but this issue persists.
Here’s my function component that wraps all the dropdown selectors in question.
import React, {useState} from 'react';
import Select from 'react-select';
import {useSelector} from "react-redux";
import "./EntityChildDropdownSelector.scss"
import {selectStyles, selectTheme} from "./SelectorStyles";
import SearchIcon from '@mui/icons-material/Search';
import PropTypes from "prop-types";
/**
EntityChildDropdownSelector for editing one attribute of an entity
@return {*}
@typedef EntitiesSelector{Selector} is a Redux selector that can be used to fetch the entities for this selector
@typedef Entity{{ id:String }} is an entity having an id
@typedef TextFormattingFunction{function} given an entity, returns it formatted as text
@typedef ClassName{string} of attribute to edit
@typedef ActivateFunction{function} to callback when a selection is made
*/
const EntityChildDropdownSelector = function (props) {
const
[isOpen, setIsOpen] = useState(false);
// option object has id and text, must be translated back and forth value <> riek field
const entities = useSelector(state => props.entitiesSelector(state)),
options = entities
.map((o) => ({value: o.id, label: props.format(o)})),
active = !!props.active ? options.find((o) => (o.value === props.active.id)) : null;
const
toggleOpen = () => {
setIsOpen(!isOpen);
},
onSelectChange = option => {
toggleOpen();
props.onActivate(option.value);
};
options?.length && !active && props.onActivate(options[0].value);
return (
<div>
<Select
autoFocus
classNamePrefix="selector"
options={options}
value={active}
backspaceRemovesValue={false}
components={{DropdownIndicator: SearchIcon, IndicatorSeparator: null}}
controlShouldRenderValue={false}
hideSelectedOptions={false}
isClearable={false}
menuIsOpen
onChange={onSelectChange}
placeholder="Search..."
styles={selectStyles(200)}
theme={selectTheme}
tabSelectsValue={false}/>
</div>
);
}
EntityChildDropdownSelector.propTypes = {
entitiesSelector: PropTypes.func.isRequired,
format: PropTypes.func,
className: PropTypes.string,
active: PropTypes.object,
onActivate: PropTypes.func.isRequired,
};
export default EntityChildDropdownSelector;
Also posted this issue to the react-select library.
Advertisement
Answer
(This is a copy of my answer given in the linked GitHub issue):
react-select uses its own theme prop for simple style customization which clashes with muis theme prop.
You should wrap SearchIcon with a function and an instance of the original DropdownIndicator to keep the props from spreading onto the icon component, but to also retain normal functionality:
import Select, { components } from "react-select";
const DropdownIndicator = (props) => (<components.DropdownIndicator {...props}>
<SearchIcon />
</components.DropdownIndicator>);
<Select
components={{
DropdownIndicator
}}
/>
PS: You could also just use a <div> element as a wrapper (with props.innerProps as props), but the default DropdownIndicator component (from components) applies basic container styling and classnames.