Skip to content

Commit 97f2fcd

Browse files
committed
fix: listbox collection simplification * 2
1 parent aa2c526 commit 97f2fcd

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed

src/components/fields/FilterListBox/FilterListBox.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
INPUT_WRAPPER_STYLES,
3737
} from '../TextInput/TextInputBase';
3838

39+
import type { Collection, Node } from '@react-types/shared';
3940
import type { FieldBaseProps } from '../../../shared';
4041

4142
type FilterFn = (textValue: string, inputValue: string) => boolean;
@@ -176,6 +177,13 @@ export interface CubeFilterListBoxProps<T>
176177
* Use with `searchValue` for controlled search input.
177178
*/
178179
onSearchChange?: (value: string) => void;
180+
181+
/**
182+
* Pre-built collection to use instead of creating a new one.
183+
* Used internally by FilterPicker to avoid duplicate collection creation.
184+
* @internal
185+
*/
186+
_internalCollection?: Collection<Node<any>>;
179187
}
180188

181189
const PROP_STYLES = [...BASE_STYLES, ...OUTER_STYLES, ...COLOR_STYLES];
@@ -265,6 +273,7 @@ export const FilterListBox = forwardRef(function FilterListBox<
265273
newCustomValueProps,
266274
searchValue: controlledSearchValue,
267275
onSearchChange,
276+
_internalCollection,
268277
...otherProps
269278
} = props;
270279

@@ -301,12 +310,15 @@ export const FilterListBox = forwardRef(function FilterListBox<
301310
}
302311
}
303312

304-
// Create a local collection for efficient key lookups and existence checks
305-
const localCollectionState = useListState({
306-
children: children as any,
307-
items: items as any,
308-
selectionMode: 'none' as any,
309-
});
313+
// Use provided collection from FilterPicker or create our own
314+
// Hook call order is stable: _internalCollection is consistent per component instance
315+
const localCollectionState = _internalCollection
316+
? { collection: _internalCollection }
317+
: useListState({
318+
children: children as any,
319+
items: items as any,
320+
selectionMode: 'none' as any,
321+
});
310322

311323
// Collect original option keys to avoid duplicating them as custom values.
312324
const originalKeys = useMemo(() => {

src/components/fields/FilterPicker/FilterPicker.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,7 @@ import {
1212
useState,
1313
} from 'react';
1414
import { FocusScope, Key, useKeyboard } from 'react-aria';
15-
import {
16-
Section as BaseSection,
17-
ListState,
18-
Item as ReactAriaItem,
19-
useListState,
20-
} from 'react-stately';
15+
import { Section as BaseSection, ListState, useListState } from 'react-stately';
2116

2217
import { useEvent } from '../../../_internal';
2318
import { useWarn } from '../../../_internal/hooks/use-warn';
@@ -790,6 +785,7 @@ export const FilterPicker = forwardRef(function FilterPicker<T extends object>(
790785
items={items ? (finalItems as typeof props.items) : undefined}
791786
// Pass an aria-label so the internal ListBox is properly labeled and React Aria doesn't warn.
792787
aria-label={`${props['aria-label'] ?? props.label ?? ''} Picker`}
788+
_internalCollection={localCollectionState.collection}
793789
selectedKey={
794790
selectionMode === 'single' ? mappedSelectedKey : undefined
795791
}

0 commit comments

Comments
 (0)