From 8a4eaf6944e4960865ae6ab3b36ce917afe8c7e2 Mon Sep 17 00:00:00 2001 From: Zeeshan Tamboli Date: Tue, 21 Jan 2025 18:56:56 +0530 Subject: [PATCH] [Autocomplete] Prevent shrink animation in uncontrolled Autocomplete when default value is set (#44873) --- .../src/useAutocomplete/useAutocomplete.js | 26 ++++++++++++------- .../useAutocomplete/useAutocomplete.test.js | 20 ++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/packages/mui-material/src/useAutocomplete/useAutocomplete.js b/packages/mui-material/src/useAutocomplete/useAutocomplete.js index 35789e85e2917c..6f5b5ca0af62cc 100644 --- a/packages/mui-material/src/useAutocomplete/useAutocomplete.js +++ b/packages/mui-material/src/useAutocomplete/useAutocomplete.js @@ -61,6 +61,14 @@ const defaultIsActiveElementInListbox = (listboxRef) => const MULTIPLE_DEFAULT_VALUE = []; +function getInputValue(value, multiple, getOptionLabel) { + if (multiple || value == null) { + return ''; + } + const optionLabel = getOptionLabel(value); + return typeof optionLabel === 'string' ? optionLabel : ''; +} + function useAutocomplete(props) { const { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -137,6 +145,12 @@ function useAutocomplete(props) { const defaultHighlighted = autoHighlight ? 0 : -1; const highlightedIndexRef = React.useRef(defaultHighlighted); + // Calculate the initial inputValue on mount only. + // Using useRef since defaultValue doesn't need to update inputValue dynamically. + const initialInputValue = React.useRef( + getInputValue(defaultValue, multiple, getOptionLabel), + ).current; + const [value, setValueState] = useControlled({ controlled: valueProp, default: defaultValue, @@ -144,7 +158,7 @@ function useAutocomplete(props) { }); const [inputValue, setInputValueState] = useControlled({ controlled: inputValueProp, - default: '', + default: initialInputValue, name: componentName, state: 'inputValue', }); @@ -159,15 +173,7 @@ function useAutocomplete(props) { if (!isOptionSelected && !clearOnBlur) { return; } - let newInputValue; - if (multiple) { - newInputValue = ''; - } else if (newValue == null) { - newInputValue = ''; - } else { - const optionLabel = getOptionLabel(newValue); - newInputValue = typeof optionLabel === 'string' ? optionLabel : ''; - } + const newInputValue = getInputValue(newValue, multiple, getOptionLabel); if (inputValue === newInputValue) { return; diff --git a/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js b/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js index 01dd8dd4b7880a..0c39bfe0724317 100644 --- a/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js +++ b/packages/mui-material/src/useAutocomplete/useAutocomplete.test.js @@ -395,4 +395,24 @@ describe('useAutocomplete', () => { fireEvent.click(button); }).not.to.throw(); }); + + describe('prop: defaultValue', () => { + it('should not trigger onInputChange when defaultValue is provided', () => { + const onInputChange = spy(); + const defaultValue = 'foo'; + + function Test() { + const { getInputProps } = useAutocomplete({ + defaultValue, + onInputChange, + options: ['foo', 'bar'], + }); + + return ; + } + + render(); + expect(onInputChange.callCount).to.equal(0); + }); + }); });