@@ -66,6 +66,14 @@ export const useCombobox = <
6666 altKey ?: boolean ;
6767 }
6868
69+ interface ICacheState {
70+ values : OptionValue [ ] ;
71+ labels : Record < string , string > ;
72+ selectedValues : OptionValue [ ] ;
73+ disabledValues : OptionValue [ ] ;
74+ hiddenValues : OptionValue [ ] ;
75+ }
76+
6977 const [ triggerContainsInput , setTriggerContainsInput ] = useState < boolean > ( ) ;
7078 const [ downshiftInputValue , setDownshiftInputValue ] = useState ( inputValue ) ;
7179 const [ matchValue , setMatchValue ] = useState ( '' ) ;
@@ -83,42 +91,44 @@ export const useCombobox = <
8391 getOptionId : ( index : number , isDisabled ?: boolean , isHidden ?: boolean ) =>
8492 `${ prefix } --option${ isDisabled ? '-disabled' : '' } ${ isHidden ? '-hidden' : '' } -${ index } `
8593 } ) ;
86- const labels : Record < string , string > = useMemo ( ( ) => ( { } ) , [ ] ) ;
87- const selectedValues : OptionValue [ ] = useMemo ( ( ) => [ ] , [ ] ) ;
88- const disabledValues : OptionValue [ ] = useMemo ( ( ) => [ ] , [ ] ) ;
89- const hiddenValues : OptionValue [ ] = useMemo ( ( ) => [ ] , [ ] ) ;
90- const values = useMemo ( ( ) => {
91- const retVal : OptionValue [ ] = [ ] ;
94+ const cache = useMemo ( ( ) => {
95+ const retVal : ICacheState = {
96+ values : [ ] ,
97+ labels : { } ,
98+ selectedValues : [ ] ,
99+ disabledValues : [ ] ,
100+ hiddenValues : [ ]
101+ } ;
92102 const setValues = ( option : IOption ) => {
93103 if ( option . disabled || option . hidden ) {
94- if ( option . disabled && ! disabledValues . includes ( option . value ) ) {
95- disabledValues . push ( option . value ) ;
104+ if ( option . disabled && ! retVal . disabledValues . includes ( option . value ) ) {
105+ retVal . disabledValues . push ( option . value ) ;
96106 }
97107
98- if ( option . hidden && ! hiddenValues . includes ( option . value ) ) {
99- hiddenValues . push ( option . value ) ;
108+ if ( option . hidden && ! retVal . hiddenValues . includes ( option . value ) ) {
109+ retVal . hiddenValues . push ( option . value ) ;
100110 }
101111 } else {
102- retVal . push ( option . value ) ;
112+ retVal . values . push ( option . value ) ;
103113
104- const disabledIndex = disabledValues . indexOf ( option . value ) ;
114+ const disabledIndex = retVal . disabledValues . indexOf ( option . value ) ;
105115
106116 if ( disabledIndex !== - 1 ) {
107- disabledValues . splice ( disabledIndex , 1 ) ;
117+ retVal . disabledValues . splice ( disabledIndex , 1 ) ;
108118 }
109119
110- const hiddenIndex = hiddenValues . indexOf ( option . value ) ;
120+ const hiddenIndex = retVal . hiddenValues . indexOf ( option . value ) ;
111121
112122 if ( hiddenIndex !== - 1 ) {
113- hiddenValues . splice ( hiddenIndex , 1 ) ;
123+ retVal . hiddenValues . splice ( hiddenIndex , 1 ) ;
114124 }
115125 }
116126
117- if ( option . selected && ! selectedValues . includes ( option . value ) ) {
118- selectedValues . push ( option . value ) ;
127+ if ( option . selected && ! retVal . selectedValues . includes ( option . value ) ) {
128+ retVal . selectedValues . push ( option . value ) ;
119129 }
120130
121- labels [ option . value ] = option . label || option . value ;
131+ retVal . labels [ option . value ] = option . label || option . value ;
122132 } ;
123133
124134 options . forEach ( option => {
@@ -130,11 +140,11 @@ export const useCombobox = <
130140 } ) ;
131141
132142 return retVal ;
133- } , [ options , disabledValues , hiddenValues , selectedValues , labels ] ) ;
134- const initialSelectionValue = isMultiselectable ? selectedValues : selectedValues [ 0 ] ;
143+ } , [ options ] ) ;
144+ const initialSelectionValue = isMultiselectable ? cache . selectedValues : cache . selectedValues [ 0 ] ;
135145 const initialInputValue = isMultiselectable
136146 ? ''
137- : toLabel ( labels , initialSelectionValue as string ) ;
147+ : toLabel ( cache . labels , initialSelectionValue as string ) ;
138148 const _defaultActiveIndex = useMemo ( ( ) => {
139149 if ( defaultActiveIndex === undefined ) {
140150 return isAutocomplete && isEditable ? 0 : undefined ;
@@ -155,7 +165,7 @@ export const useCombobox = <
155165 */
156166
157167 if ( selectionValue === undefined || selectionValue === null ) {
158- if ( ! isMultiselectable && selectedValues . length > 1 ) {
168+ if ( ! isMultiselectable && cache . selectedValues . length > 1 ) {
159169 throw new Error ( 'Error: expected useCombobox `options` to have no more than one selected.' ) ;
160170 }
161171 }
@@ -240,7 +250,7 @@ export const useCombobox = <
240250 // Fix Downshift standard last option activation on listbox
241251 // expansion. Addresses problems with initial multiselectable and
242252 // overeager `defaultActiveIndex` comboboxes.
243- changes . highlightedIndex = values . length - 1 ;
253+ changes . highlightedIndex = cache . values . length - 1 ;
244254 }
245255
246256 break ;
@@ -297,7 +307,7 @@ export const useCombobox = <
297307 return changes ;
298308 } ;
299309
300- const transformValue = ( value : OptionValue | null ) => ( value ? toLabel ( labels , value ) : '' ) ;
310+ const transformValue = ( value : OptionValue | null ) => ( value ? toLabel ( cache . labels , value ) : '' ) ;
301311
302312 /** Hooks */
303313
@@ -318,7 +328,7 @@ export const useCombobox = <
318328 toggleButtonId : idRef . current . trigger ,
319329 menuId : idRef . current . listbox ,
320330 getItemId : idRef . current . getOptionId ,
321- items : values ,
331+ items : cache . values ,
322332 inputValue : downshiftInputValue ,
323333 initialInputValue,
324334 itemToString : transformValue as any /* HACK around Downshift's generic type overuse */ ,
@@ -394,7 +404,7 @@ export const useCombobox = <
394404 _selectionValue . length - 1 // multiselectable most recent
395405 ]
396406 : _selectionValue ;
397- const index = values . findIndex ( current => current === value ) ;
407+ const index = cache . values . findIndex ( current => current === value ) ;
398408
399409 if ( index !== - 1 ) {
400410 setActiveIndex ( index ) ;
@@ -410,7 +420,7 @@ export const useCombobox = <
410420 _isExpanded ,
411421 _selectionValue ,
412422 _inputValue ,
413- values ,
423+ cache . values ,
414424 _defaultActiveIndex ,
415425 setActiveIndex
416426 ]
@@ -522,7 +532,7 @@ export const useCombobox = <
522532 event . preventDefault ( ) ;
523533
524534 if ( _activeIndex !== - 1 ) {
525- setDownshiftSelection ( values [ _activeIndex ] ) ;
535+ setDownshiftSelection ( cache . values [ _activeIndex ] ) ;
526536 }
527537
528538 if ( ! isMultiselectable ) {
@@ -551,15 +561,17 @@ export const useCombobox = <
551561 : _selectionValue ;
552562
553563 if ( offsetValue !== null ) {
554- offset = values . findIndex ( current => current === offsetValue ) ;
564+ offset = cache . values . findIndex ( current => current === offsetValue ) ;
555565 }
556566 }
557567
558- for ( let index = 0 ; index < values . length ; index ++ ) {
559- const valueIndex = ( index + offset ) % values . length ;
560- const value = values [ valueIndex ] ;
568+ for ( let index = 0 ; index < cache . values . length ; index ++ ) {
569+ const valueIndex = ( index + offset ) % cache . values . length ;
570+ const value = cache . values [ valueIndex ] ;
561571
562- if ( toLabel ( labels , value ) . toLowerCase ( ) . startsWith ( _matchValue . toLowerCase ( ) ) ) {
572+ if (
573+ toLabel ( cache . labels , value ) . toLowerCase ( ) . startsWith ( _matchValue . toLowerCase ( ) )
574+ ) {
563575 setActiveIndex ( valueIndex ) ;
564576 break ;
565577 }
@@ -596,8 +608,8 @@ export const useCombobox = <
596608 setActiveIndex ,
597609 setDownshiftSelection ,
598610 matchValue ,
599- values ,
600- labels ,
611+ cache . values ,
612+ cache . labels ,
601613 triggerContainsInput ,
602614 isAutocomplete ,
603615 isEditable ,
@@ -840,7 +852,7 @@ export const useCombobox = <
840852 'aria-selected' : ariaSelected ,
841853 id : option
842854 ? idRef . current . getOptionId (
843- hiddenValues . indexOf ( option . value ) ,
855+ cache . hiddenValues . indexOf ( option . value ) ,
844856 option . disabled ,
845857 option . hidden
846858 )
@@ -858,7 +870,7 @@ export const useCombobox = <
858870 'aria-selected' : ariaSelected ,
859871 id : option
860872 ? idRef . current . getOptionId (
861- disabledValues . indexOf ( option . value ) ,
873+ cache . disabledValues . indexOf ( option . value ) ,
862874 option . disabled ,
863875 option . hidden
864876 )
@@ -870,14 +882,20 @@ export const useCombobox = <
870882
871883 return getDownshiftOptionProps < any > ( {
872884 item : option . value ,
873- index : values . indexOf ( option . value ) ,
885+ index : cache . values . indexOf ( option . value ) ,
874886 'aria-disabled' : undefined ,
875887 'aria-hidden' : undefined ,
876888 'aria-selected' : ariaSelected ,
877889 ...optionProps
878890 } as IDownshiftOptionProps < OptionValue > ) ;
879891 } ,
880- [ getDownshiftOptionProps , disabledValues , hiddenValues , values , _selectionValue ]
892+ [
893+ getDownshiftOptionProps ,
894+ cache . disabledValues ,
895+ cache . hiddenValues ,
896+ cache . values ,
897+ _selectionValue
898+ ]
881899 ) ;
882900
883901 const getMessageProps = useCallback < IUseComboboxReturnValue [ 'getMessageProps' ] > (
@@ -914,21 +932,21 @@ export const useCombobox = <
914932 if ( Array . isArray ( _selectionValue ) ) {
915933 return _selectionValue . map ( value => ( {
916934 value,
917- label : labels [ value ] ,
918- disabled : disabledValues . includes ( value ) ,
919- hidden : hiddenValues . includes ( value )
935+ label : cache . labels [ value ] ,
936+ disabled : cache . disabledValues . includes ( value ) ,
937+ hidden : cache . hiddenValues . includes ( value )
920938 } ) ) ;
921939 } else if ( _selectionValue ) {
922940 return {
923941 value : _selectionValue ,
924- label : toLabel ( labels , _selectionValue ) ,
925- disabled : disabledValues . includes ( _selectionValue ) ,
926- hidden : hiddenValues . includes ( _selectionValue )
942+ label : toLabel ( cache . labels , _selectionValue ) ,
943+ disabled : cache . disabledValues . includes ( _selectionValue ) ,
944+ hidden : cache . hiddenValues . includes ( _selectionValue )
927945 } ;
928946 }
929947
930948 return null ;
931- } , [ _selectionValue , disabledValues , hiddenValues , labels ] ) ;
949+ } , [ _selectionValue , cache . disabledValues , cache . hiddenValues , cache . labels ] ) ;
932950
933951 return useMemo < IUseComboboxReturnValue > (
934952 ( ) => ( {
@@ -945,13 +963,13 @@ export const useCombobox = <
945963 /* state */
946964 selection,
947965 isExpanded : _isExpanded ,
948- activeValue : values [ _activeIndex ] ,
966+ activeValue : cache . values [ _activeIndex ] ,
949967 inputValue : _inputValue ,
950968 /* actions */
951969 removeSelection
952970 } ) ,
953971 [
954- values ,
972+ cache . values ,
955973 selection ,
956974 _isExpanded ,
957975 _activeIndex ,
0 commit comments