Skip to content

Commit e0e7f41

Browse files
committed
fix(ComboBox): optimize collection
1 parent 0718146 commit e0e7f41

File tree

1 file changed

+18
-13
lines changed

1 file changed

+18
-13
lines changed

src/components/fields/ComboBox/ComboBox.tsx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
useOverlay,
1919
useOverlayPosition,
2020
} from 'react-aria';
21-
import { Section as BaseSection } from 'react-stately';
21+
import { Section as BaseSection, useListState } from 'react-stately';
2222

2323
import { useEvent } from '../../../_internal';
2424
import { CloseIcon, DirectionIcon, LoadingIcon } from '../../../icons';
@@ -896,7 +896,7 @@ function ComboBoxOverlay({
896896
const placementDirection = placement?.split(' ')[0] || direction;
897897

898898
const overlayContent = (
899-
<DisplayTransition exposeUnmounted isShown={isOpen}>
899+
<DisplayTransition isShown={isOpen}>
900900
{({ phase, isShown, ref: transitionRef }) => (
901901
<ComboBoxOverlayElement
902902
{...mergeProps(
@@ -1199,6 +1199,14 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
11991199
? filteredChildren
12001200
: frozenFilteredChildrenRef.current ?? filteredChildren;
12011201

1202+
// Create local collection state for reading item data (labels, etc.)
1203+
// This allows us to read item labels even before the popover opens
1204+
const localCollectionState = useListState({
1205+
children: displayedFilteredChildren,
1206+
items: sortedItems,
1207+
selectionMode: 'none', // Don't manage selection in this state
1208+
});
1209+
12021210
const { isFocused, focusProps } = useFocus({ isDisabled });
12031211

12041212
// Composite blur handler - fires when focus leaves the entire component
@@ -1268,11 +1276,14 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
12681276
const listStateRef = useRef<any>(null);
12691277
const focusInitAttemptsRef = useRef(0);
12701278

1271-
// Helper to get label from collection item
1272-
const getItemLabel = useCallback((key: Key): string => {
1273-
const item = listStateRef.current?.collection?.getItem(key);
1274-
return item?.textValue || String(key);
1275-
}, []);
1279+
// Helper to get label from local collection
1280+
const getItemLabel = useCallback(
1281+
(key: Key): string => {
1282+
const item = localCollectionState?.collection?.getItem(key);
1283+
return item?.textValue || String(key);
1284+
},
1285+
[localCollectionState?.collection],
1286+
);
12761287

12771288
// Selection change handler
12781289
const handleSelectionChange = useEvent((selection: Key | Key[] | null) => {
@@ -1360,9 +1371,6 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
13601371

13611372
// Priority 2: fall back to defaultSelectedKey's label
13621373
if (defaultSelectedKey) {
1363-
// Wait for collection to be ready
1364-
if (!listStateRef.current?.collection) return;
1365-
13661374
const label = getItemLabel(defaultSelectedKey);
13671375

13681376
setInternalInputValue(label);
@@ -1382,9 +1390,6 @@ export const ComboBox = forwardRef(function ComboBox<T extends object>(
13821390
// Only run when selectedKey is controlled but inputValue is uncontrolled
13831391
if (!isControlledKey || isControlledInput) return;
13841392

1385-
// Wait for collection to be ready
1386-
if (!listStateRef.current?.collection) return;
1387-
13881393
// Get the expected label for the current selection
13891394
const expectedLabel =
13901395
effectiveSelectedKey != null ? getItemLabel(effectiveSelectedKey) : '';

0 commit comments

Comments
 (0)