I am getting an error I theoretically understand, but practically cannot solve.
import React, {CSSProperties, useEffect, useRef, useState} from 'react';
import {SelectOption, useSelect} from '@mui/base';
import {useTranslation} from 'react-i18next';
export interface DropdownInputProps {
loading?: boolean,
label: string,
options: DropdownOption[];
placeholder?: string,
required?: boolean,
setSelection: (selection: DropdownOption[] | null) => void,
width?: number,
readOnly?: boolean,
}
export const DropdownInput = ({
loading,
label,
options,
placeholder,
required,
setSelection,
defaultValue,
width,
readOnly,
}: DropdownInputProps) => {
const menuRef = useRef(null)
const [value, setValue] = useState<number | null>(null)
const [listening, setListening] = useState(false);
const [listBoxVisible, setListBoxVisible] = useState(false);
const listboxRef = React.useRef<HTMLUListElement>(null);
const {
getButtonProps,
getListboxProps,
getOptionProps,
getOptionState,
} = useSelect({
listboxRef,
onOpenChange: () => setListBoxVisible(!listBoxVisible),
onChange: (event, newValue) => _onChange(newValue),
open: listBoxVisible,
options,
value,
defaultValue,
});
const {t} = useTranslation();
useEffect(() => {
if (defaultValue !== undefined) setValue(defaultValue)
}, [defaultValue]);
const _onChange = (value: number | null) => {
setValue(value)
setSelection(options.filter(option => option.value === value) as DropdownOption[] | null)
}
const _renderStringInInput = () => {
return ...
}
const _getSelectedValue = (value: number | null, options: SelectOption<any>[]) => {
const selectedOption = options.find(option => option.value === value);
if (selectedOption !== undefined) return t(`${selectedOption.label?.toString()}`)
return null;
}
const _renderListBox = (theme: ThemeProps) => {...}
const _renderInput = (theme: ThemeProps) => {
const ariaForId = `:dropdown-input-${guidGenerator()}:`
const {colors} = theme
const commonProps: CommonProps = {
readOnly: readOnly,
style: {
color: _getSelectedValue(value, options) ? 'inherit' : colors.lightGreyDarker,
borderColor: formError ? colors.warningMain : 'inherit'
},
placeholder: placeholder ? t(placeholder) : '--',
className: clsx('input-field', readOnly && 'input-disabled', inputClasses),
value: defaultValue ? undefined : _renderStringInInput(),
defaultValue: value ? undefined : _renderStringInInput(),
type: "button",
id: ariaForId
}
if (formError || dataError) {
commonProps["aria-invalid"] = "true"
commonProps["aria-errormessage"] = t(`${ariaErrorMessage}`)
}
return <>
<Text
style={setLabelColor(theme, formError || dataError, readOnly, labelColor)}
required={required}
ariaFor={ariaForId}
variant={'label'}>
{label}
</Text>
<input
{...getButtonProps()}
{...commonProps}
id={ariaForId}/>
</>
}
return <ThemeContext.Consumer>
{(theme) =>
<div
className={clsx('input-container', containerClasses)}
style={{width: width, ...style}}>
{_renderInput(theme)} />
}
</ThemeContext.Consumer>
}
And with this I get the warning
Warning: Context.Consumer contains an input of type button with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props.
Which I do not understand. value
is not coming from the parent, only defautlValue
. Thus, the local state is managed by DropdownInput />
itself. Here
value: defaultValue ? undefined : _renderStringInInput(),
defaultValue: value ? undefined : _renderStringInInput(),
I either assign value
or defaultValue
, depending if there is something in there. So why am I getting this warning?