diff --git a/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js b/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js index 882299e15c49..96859ac0ae93 100644 --- a/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js +++ b/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js @@ -304,6 +304,34 @@ describe('MultiSelect', () => { ).toBeInstanceOf(HTMLElement); }); + it('should trigger onChange with selected items', async () => { + let selectedItems = []; + const testFunction = jest.fn((e) => (selectedItems = e?.selectedItems)); + const items = generateItems(4, generateGenericItem); + const label = 'test-label'; + const { container } = render( + + ); + + // eslint-disable-next-line testing-library/prefer-screen-queries + const labelNode = getByText(container, label); + await userEvent.click(labelNode); + + const [item] = items; + // eslint-disable-next-line testing-library/prefer-screen-queries + const itemNode = getByText(container, item.label); + + await userEvent.click(itemNode); + // Assert that the onChange callback returned the selected items and assigned it to selectedItems + expect(testFunction.mock.results[0].value).toEqual(selectedItems); + }); + it('should place the given id on the ___ node when passed in as a prop', () => { const items = generateItems(4, generateGenericItem); const label = 'test-label'; diff --git a/packages/react/src/internal/Selection.js b/packages/react/src/internal/Selection.js index b689fed79103..35bc753c8ddd 100644 --- a/packages/react/src/internal/Selection.js +++ b/packages/react/src/internal/Selection.js @@ -36,42 +36,39 @@ export function useSelection({ const [uncontrolledItems, setUncontrolledItems] = useState(initialSelectedItems); const isControlled = !!controlledItems; - const selectedItems = isControlled ? controlledItems : uncontrolledItems; + const [selectedItems, setSelectedItems] = useState( + isControlled ? controlledItems : uncontrolledItems + ); + useEffect(() => { + callOnChangeHandler({ + isControlled, + isMounted: isMounted.current, + onChangeHandlerControlled: savedOnChange.current, + onChangeHandlerUncontrolled: setUncontrolledItems, + selectedItems: selectedItems, + }); + }, [isControlled, isMounted, selectedItems]); + const onItemChange = useCallback( (item) => { if (disabled) { return; } - let selectedIndex; selectedItems.forEach((selectedItem, index) => { if (isEqual(selectedItem, item)) { selectedIndex = index; } }); - let newSelectedItems; if (selectedIndex === undefined) { - newSelectedItems = selectedItems.concat(item); - callOnChangeHandler({ - isControlled, - isMounted: isMounted.current, - onChangeHandlerControlled: savedOnChange.current, - onChangeHandlerUncontrolled: setUncontrolledItems, - selectedItems: newSelectedItems, - }); + setSelectedItems((selectedItems) => selectedItems.concat(item)); return; } - - newSelectedItems = removeAtIndex(selectedItems, selectedIndex); - callOnChangeHandler({ - isControlled, - isMounted: isMounted.current, - onChangeHandlerControlled: savedOnChange.current, - onChangeHandlerUncontrolled: setUncontrolledItems, - selectedItems: newSelectedItems, - }); + setSelectedItems((selectedItems) => + removeAtIndex(selectedItems, selectedIndex) + ); }, - [disabled, isControlled, selectedItems] + [disabled, selectedItems] ); const clearSelection = useCallback(() => { @@ -83,7 +80,7 @@ export function useSelection({ isMounted: isMounted.current, onChangeHandlerControlled: savedOnChange.current, onChangeHandlerUncontrolled: setUncontrolledItems, - selectedItems: [], + selectedItems: setSelectedItems([]), }); }, [disabled, isControlled]); @@ -186,7 +183,6 @@ export default class Selection extends React.Component { onItemChange: this.handleOnItemChange, clearSelection: this.handleClearSelection, }; - if (render !== undefined) { return render(renderProps); }