downshift 8.2.3 → 8.2.4-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1460,7 +1460,7 @@ MIT
1460
1460
  [npm]: https://www.npmjs.com/
1461
1461
  [node]: https://nodejs.org
1462
1462
  [build-badge]:
1463
- https://img.shields.io/github/workflow/status/downshift-js/downshift/validate?logo=github&style=flat-square
1463
+ https://img.shields.io/github/actions/workflow/status/downshift-js/downshift/validate.yml?branch=master&logo=github&style=flat-square
1464
1464
  [build]:
1465
1465
  https://github.com/downshift-js/downshift/actions?query=workflow%3Avalidate+branch%3Amaster
1466
1466
  [coverage-badge]:
@@ -1697,9 +1697,10 @@ function useLatestRef(val) {
1697
1697
  * @param {Function} reducer Reducer function from downshift.
1698
1698
  * @param {Object} props The hook props, also passed to createInitialState.
1699
1699
  * @param {Function} createInitialState Function that returns the initial state.
1700
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1700
1701
  * @returns {Array} An array with the state and an action dispatcher.
1701
1702
  */
1702
- function useEnhancedReducer(reducer, props, createInitialState) {
1703
+ function useEnhancedReducer(reducer, props, createInitialState, isStateEqual) {
1703
1704
  var prevStateRef = React.useRef();
1704
1705
  var actionRef = React.useRef();
1705
1706
  var enhancedReducer = React.useCallback(function (state, action) {
@@ -1722,11 +1723,12 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1722
1723
  }, [propsRef]);
1723
1724
  var action = actionRef.current;
1724
1725
  React.useEffect(function () {
1725
- if (action && prevStateRef.current && prevStateRef.current !== state) {
1726
+ var stateChanged = prevStateRef.current && !isStateEqual(prevStateRef.current, state);
1727
+ if (action && stateChanged) {
1726
1728
  callOnChangeProps(action, getState(prevStateRef.current, action.props), state);
1727
1729
  }
1728
1730
  prevStateRef.current = state;
1729
- }, [state, props, action]);
1731
+ }, [state, props, action, isStateEqual]);
1730
1732
  return [state, dispatchWithProps];
1731
1733
  }
1732
1734
 
@@ -1737,10 +1739,11 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1737
1739
  * @param {Function} reducer Reducer function from downshift.
1738
1740
  * @param {Object} props The hook props, also passed to createInitialState.
1739
1741
  * @param {Function} createInitialState Function that returns the initial state.
1742
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1740
1743
  * @returns {Array} An array with the state and an action dispatcher.
1741
1744
  */
1742
- function useControlledReducer$1(reducer, props, createInitialState) {
1743
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
1745
+ function useControlledReducer$1(reducer, props, createInitialState, isStateEqual) {
1746
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
1744
1747
  state = _useEnhancedReducer[0],
1745
1748
  dispatch = _useEnhancedReducer[1];
1746
1749
  return [getState(state, props), dispatch];
@@ -2022,6 +2025,18 @@ function getChangesOnSelection(props, highlightedIndex, inputValue) {
2022
2025
  }));
2023
2026
  }
2024
2027
 
2028
+ /**
2029
+ * Check if a state is equal for dropdowns, by comparing isOpen, inputValue, highlightedIndex and selected item.
2030
+ * Used by useSelect and useCombobox.
2031
+ *
2032
+ * @param {Object} prevState
2033
+ * @param {Object} newState
2034
+ * @returns {boolean} Wheather the states are deeply equal.
2035
+ */
2036
+ function isDropdownsStateEqual(prevState, newState) {
2037
+ return prevState.isOpen === newState.isOpen && prevState.inputValue === newState.inputValue && prevState.highlightedIndex === newState.highlightedIndex && prevState.selectedItem === newState.selectedItem;
2038
+ }
2039
+
2025
2040
  // Shared between all exports.
2026
2041
  var commonPropTypes = {
2027
2042
  environment: PropTypes__default["default"].shape({
@@ -2344,14 +2359,13 @@ function useSelect(userProps) {
2344
2359
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2345
2360
  getA11yStatusMessage = props.getA11yStatusMessage;
2346
2361
  // Initial state depending on controlled props.
2347
- var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2),
2362
+ var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2, isDropdownsStateEqual),
2348
2363
  state = _useControlledReducer[0],
2349
2364
  dispatch = _useControlledReducer[1];
2350
2365
  var isOpen = state.isOpen,
2351
2366
  highlightedIndex = state.highlightedIndex,
2352
2367
  selectedItem = state.selectedItem,
2353
2368
  inputValue = state.inputValue;
2354
-
2355
2369
  // Element efs.
2356
2370
  var toggleButtonRef = React.useRef(null);
2357
2371
  var menuRef = React.useRef(null);
@@ -2829,11 +2843,12 @@ var propTypes$1 = _extends__default["default"]({}, commonDropdownPropTypes, {
2829
2843
  * @param {Function} reducer Reducer function from downshift.
2830
2844
  * @param {Object} props The hook props, also passed to createInitialState.
2831
2845
  * @param {Function} createInitialState Function that returns the initial state.
2846
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
2832
2847
  * @returns {Array} An array with the state and an action dispatcher.
2833
2848
  */
2834
- function useControlledReducer(reducer, props, createInitialState) {
2849
+ function useControlledReducer(reducer, props, createInitialState, isStateEqual) {
2835
2850
  var previousSelectedItemRef = React.useRef();
2836
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
2851
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
2837
2852
  state = _useEnhancedReducer[0],
2838
2853
  dispatch = _useEnhancedReducer[1];
2839
2854
 
@@ -3007,7 +3022,7 @@ function useCombobox(userProps) {
3007
3022
  getA11ySelectionMessage = props.getA11ySelectionMessage,
3008
3023
  itemToString = props.itemToString;
3009
3024
  // Initial state depending on controlled props.
3010
- var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1),
3025
+ var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1, isDropdownsStateEqual),
3011
3026
  state = _useControlledReducer[0],
3012
3027
  dispatch = _useControlledReducer[1];
3013
3028
  var isOpen = state.isOpen,
@@ -3492,6 +3507,18 @@ function getA11yRemovalMessage(selectionParameters) {
3492
3507
  itemToStringLocal = selectionParameters.itemToString;
3493
3508
  return itemToStringLocal(removedSelectedItem) + " has been removed.";
3494
3509
  }
3510
+
3511
+ /**
3512
+ * Check if a state is equal for taglist, by comparing active index and selected items.
3513
+ * Used by useSelect and useCombobox.
3514
+ *
3515
+ * @param {Object} prevState
3516
+ * @param {Object} newState
3517
+ * @returns {boolean} Wheather the states are deeply equal.
3518
+ */
3519
+ function isStateEqual(prevState, newState) {
3520
+ return prevState.selectedItems === newState.selectedItems && prevState.activeIndex === newState.activeIndex;
3521
+ }
3495
3522
  var propTypes = _extends__default["default"]({}, commonPropTypes, {
3496
3523
  selectedItems: PropTypes__default["default"].array,
3497
3524
  initialSelectedItems: PropTypes__default["default"].array,
@@ -3681,7 +3708,7 @@ function useMultipleSelection(userProps) {
3681
3708
  keyNavigationPrevious = props.keyNavigationPrevious;
3682
3709
 
3683
3710
  // Reducer init.
3684
- var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState),
3711
+ var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState, isStateEqual),
3685
3712
  state = _useControlledReducer[0],
3686
3713
  dispatch = _useControlledReducer[1];
3687
3714
  var activeIndex = state.activeIndex,
@@ -1684,9 +1684,10 @@ function useLatestRef(val) {
1684
1684
  * @param {Function} reducer Reducer function from downshift.
1685
1685
  * @param {Object} props The hook props, also passed to createInitialState.
1686
1686
  * @param {Function} createInitialState Function that returns the initial state.
1687
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1687
1688
  * @returns {Array} An array with the state and an action dispatcher.
1688
1689
  */
1689
- function useEnhancedReducer(reducer, props, createInitialState) {
1690
+ function useEnhancedReducer(reducer, props, createInitialState, isStateEqual) {
1690
1691
  var prevStateRef = useRef();
1691
1692
  var actionRef = useRef();
1692
1693
  var enhancedReducer = useCallback(function (state, action) {
@@ -1709,11 +1710,12 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1709
1710
  }, [propsRef]);
1710
1711
  var action = actionRef.current;
1711
1712
  useEffect(function () {
1712
- if (action && prevStateRef.current && prevStateRef.current !== state) {
1713
+ var stateChanged = prevStateRef.current && !isStateEqual(prevStateRef.current, state);
1714
+ if (action && stateChanged) {
1713
1715
  callOnChangeProps(action, getState(prevStateRef.current, action.props), state);
1714
1716
  }
1715
1717
  prevStateRef.current = state;
1716
- }, [state, props, action]);
1718
+ }, [state, props, action, isStateEqual]);
1717
1719
  return [state, dispatchWithProps];
1718
1720
  }
1719
1721
 
@@ -1724,10 +1726,11 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1724
1726
  * @param {Function} reducer Reducer function from downshift.
1725
1727
  * @param {Object} props The hook props, also passed to createInitialState.
1726
1728
  * @param {Function} createInitialState Function that returns the initial state.
1729
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1727
1730
  * @returns {Array} An array with the state and an action dispatcher.
1728
1731
  */
1729
- function useControlledReducer$1(reducer, props, createInitialState) {
1730
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
1732
+ function useControlledReducer$1(reducer, props, createInitialState, isStateEqual) {
1733
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
1731
1734
  state = _useEnhancedReducer[0],
1732
1735
  dispatch = _useEnhancedReducer[1];
1733
1736
  return [getState(state, props), dispatch];
@@ -2009,6 +2012,18 @@ function getChangesOnSelection(props, highlightedIndex, inputValue) {
2009
2012
  }));
2010
2013
  }
2011
2014
 
2015
+ /**
2016
+ * Check if a state is equal for dropdowns, by comparing isOpen, inputValue, highlightedIndex and selected item.
2017
+ * Used by useSelect and useCombobox.
2018
+ *
2019
+ * @param {Object} prevState
2020
+ * @param {Object} newState
2021
+ * @returns {boolean} Wheather the states are deeply equal.
2022
+ */
2023
+ function isDropdownsStateEqual(prevState, newState) {
2024
+ return prevState.isOpen === newState.isOpen && prevState.inputValue === newState.inputValue && prevState.highlightedIndex === newState.highlightedIndex && prevState.selectedItem === newState.selectedItem;
2025
+ }
2026
+
2012
2027
  // Shared between all exports.
2013
2028
  var commonPropTypes = {
2014
2029
  environment: PropTypes.shape({
@@ -2331,14 +2346,13 @@ function useSelect(userProps) {
2331
2346
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2332
2347
  getA11yStatusMessage = props.getA11yStatusMessage;
2333
2348
  // Initial state depending on controlled props.
2334
- var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2),
2349
+ var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2, isDropdownsStateEqual),
2335
2350
  state = _useControlledReducer[0],
2336
2351
  dispatch = _useControlledReducer[1];
2337
2352
  var isOpen = state.isOpen,
2338
2353
  highlightedIndex = state.highlightedIndex,
2339
2354
  selectedItem = state.selectedItem,
2340
2355
  inputValue = state.inputValue;
2341
-
2342
2356
  // Element efs.
2343
2357
  var toggleButtonRef = useRef(null);
2344
2358
  var menuRef = useRef(null);
@@ -2816,11 +2830,12 @@ var propTypes$1 = _extends({}, commonDropdownPropTypes, {
2816
2830
  * @param {Function} reducer Reducer function from downshift.
2817
2831
  * @param {Object} props The hook props, also passed to createInitialState.
2818
2832
  * @param {Function} createInitialState Function that returns the initial state.
2833
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
2819
2834
  * @returns {Array} An array with the state and an action dispatcher.
2820
2835
  */
2821
- function useControlledReducer(reducer, props, createInitialState) {
2836
+ function useControlledReducer(reducer, props, createInitialState, isStateEqual) {
2822
2837
  var previousSelectedItemRef = useRef();
2823
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
2838
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
2824
2839
  state = _useEnhancedReducer[0],
2825
2840
  dispatch = _useEnhancedReducer[1];
2826
2841
 
@@ -2994,7 +3009,7 @@ function useCombobox(userProps) {
2994
3009
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2995
3010
  itemToString = props.itemToString;
2996
3011
  // Initial state depending on controlled props.
2997
- var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1),
3012
+ var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1, isDropdownsStateEqual),
2998
3013
  state = _useControlledReducer[0],
2999
3014
  dispatch = _useControlledReducer[1];
3000
3015
  var isOpen = state.isOpen,
@@ -3479,6 +3494,18 @@ function getA11yRemovalMessage(selectionParameters) {
3479
3494
  itemToStringLocal = selectionParameters.itemToString;
3480
3495
  return itemToStringLocal(removedSelectedItem) + " has been removed.";
3481
3496
  }
3497
+
3498
+ /**
3499
+ * Check if a state is equal for taglist, by comparing active index and selected items.
3500
+ * Used by useSelect and useCombobox.
3501
+ *
3502
+ * @param {Object} prevState
3503
+ * @param {Object} newState
3504
+ * @returns {boolean} Wheather the states are deeply equal.
3505
+ */
3506
+ function isStateEqual(prevState, newState) {
3507
+ return prevState.selectedItems === newState.selectedItems && prevState.activeIndex === newState.activeIndex;
3508
+ }
3482
3509
  var propTypes = _extends({}, commonPropTypes, {
3483
3510
  selectedItems: PropTypes.array,
3484
3511
  initialSelectedItems: PropTypes.array,
@@ -3668,7 +3695,7 @@ function useMultipleSelection(userProps) {
3668
3695
  keyNavigationPrevious = props.keyNavigationPrevious;
3669
3696
 
3670
3697
  // Reducer init.
3671
- var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState),
3698
+ var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState, isStateEqual),
3672
3699
  state = _useControlledReducer[0],
3673
3700
  dispatch = _useControlledReducer[1];
3674
3701
  var activeIndex = state.activeIndex,
@@ -1593,9 +1593,10 @@ function useLatestRef(val) {
1593
1593
  * @param {Function} reducer Reducer function from downshift.
1594
1594
  * @param {Object} props The hook props, also passed to createInitialState.
1595
1595
  * @param {Function} createInitialState Function that returns the initial state.
1596
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1596
1597
  * @returns {Array} An array with the state and an action dispatcher.
1597
1598
  */
1598
- function useEnhancedReducer(reducer, props, createInitialState) {
1599
+ function useEnhancedReducer(reducer, props, createInitialState, isStateEqual) {
1599
1600
  var prevStateRef = React.useRef();
1600
1601
  var actionRef = React.useRef();
1601
1602
  var enhancedReducer = React.useCallback(function (state, action) {
@@ -1618,11 +1619,12 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1618
1619
  }, [propsRef]);
1619
1620
  var action = actionRef.current;
1620
1621
  React.useEffect(function () {
1621
- if (action && prevStateRef.current && prevStateRef.current !== state) {
1622
+ var stateChanged = prevStateRef.current && !isStateEqual(prevStateRef.current, state);
1623
+ if (action && stateChanged) {
1622
1624
  callOnChangeProps(action, getState(prevStateRef.current, action.props), state);
1623
1625
  }
1624
1626
  prevStateRef.current = state;
1625
- }, [state, props, action]);
1627
+ }, [state, props, action, isStateEqual]);
1626
1628
  return [state, dispatchWithProps];
1627
1629
  }
1628
1630
 
@@ -1633,10 +1635,11 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1633
1635
  * @param {Function} reducer Reducer function from downshift.
1634
1636
  * @param {Object} props The hook props, also passed to createInitialState.
1635
1637
  * @param {Function} createInitialState Function that returns the initial state.
1638
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1636
1639
  * @returns {Array} An array with the state and an action dispatcher.
1637
1640
  */
1638
- function useControlledReducer$1(reducer, props, createInitialState) {
1639
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
1641
+ function useControlledReducer$1(reducer, props, createInitialState, isStateEqual) {
1642
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
1640
1643
  state = _useEnhancedReducer[0],
1641
1644
  dispatch = _useEnhancedReducer[1];
1642
1645
  return [getState(state, props), dispatch];
@@ -1877,6 +1880,18 @@ function getChangesOnSelection(props, highlightedIndex, inputValue) {
1877
1880
  }));
1878
1881
  }
1879
1882
 
1883
+ /**
1884
+ * Check if a state is equal for dropdowns, by comparing isOpen, inputValue, highlightedIndex and selected item.
1885
+ * Used by useSelect and useCombobox.
1886
+ *
1887
+ * @param {Object} prevState
1888
+ * @param {Object} newState
1889
+ * @returns {boolean} Wheather the states are deeply equal.
1890
+ */
1891
+ function isDropdownsStateEqual(prevState, newState) {
1892
+ return prevState.isOpen === newState.isOpen && prevState.inputValue === newState.inputValue && prevState.highlightedIndex === newState.highlightedIndex && prevState.selectedItem === newState.selectedItem;
1893
+ }
1894
+
1880
1895
  // Shared between all exports.
1881
1896
  var commonPropTypes = {
1882
1897
  environment: PropTypes__default["default"].shape({
@@ -2199,14 +2214,13 @@ function useSelect(userProps) {
2199
2214
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2200
2215
  getA11yStatusMessage = props.getA11yStatusMessage;
2201
2216
  // Initial state depending on controlled props.
2202
- var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2),
2217
+ var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2, isDropdownsStateEqual),
2203
2218
  state = _useControlledReducer[0],
2204
2219
  dispatch = _useControlledReducer[1];
2205
2220
  var isOpen = state.isOpen,
2206
2221
  highlightedIndex = state.highlightedIndex,
2207
2222
  selectedItem = state.selectedItem,
2208
2223
  inputValue = state.inputValue;
2209
-
2210
2224
  // Element efs.
2211
2225
  var toggleButtonRef = React.useRef(null);
2212
2226
  var menuRef = React.useRef(null);
@@ -2668,11 +2682,12 @@ var propTypes$1 = _extends__default["default"]({}, commonDropdownPropTypes, {
2668
2682
  * @param {Function} reducer Reducer function from downshift.
2669
2683
  * @param {Object} props The hook props, also passed to createInitialState.
2670
2684
  * @param {Function} createInitialState Function that returns the initial state.
2685
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
2671
2686
  * @returns {Array} An array with the state and an action dispatcher.
2672
2687
  */
2673
- function useControlledReducer(reducer, props, createInitialState) {
2688
+ function useControlledReducer(reducer, props, createInitialState, isStateEqual) {
2674
2689
  var previousSelectedItemRef = React.useRef();
2675
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
2690
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
2676
2691
  state = _useEnhancedReducer[0],
2677
2692
  dispatch = _useEnhancedReducer[1];
2678
2693
 
@@ -2846,7 +2861,7 @@ function useCombobox(userProps) {
2846
2861
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2847
2862
  itemToString = props.itemToString;
2848
2863
  // Initial state depending on controlled props.
2849
- var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1),
2864
+ var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1, isDropdownsStateEqual),
2850
2865
  state = _useControlledReducer[0],
2851
2866
  dispatch = _useControlledReducer[1];
2852
2867
  var isOpen = state.isOpen,
@@ -3338,6 +3353,18 @@ function getA11yRemovalMessage(selectionParameters) {
3338
3353
  itemToStringLocal = selectionParameters.itemToString;
3339
3354
  return itemToStringLocal(removedSelectedItem) + " has been removed.";
3340
3355
  }
3356
+
3357
+ /**
3358
+ * Check if a state is equal for taglist, by comparing active index and selected items.
3359
+ * Used by useSelect and useCombobox.
3360
+ *
3361
+ * @param {Object} prevState
3362
+ * @param {Object} newState
3363
+ * @returns {boolean} Wheather the states are deeply equal.
3364
+ */
3365
+ function isStateEqual(prevState, newState) {
3366
+ return prevState.selectedItems === newState.selectedItems && prevState.activeIndex === newState.activeIndex;
3367
+ }
3341
3368
  var propTypes = _extends__default["default"]({}, commonPropTypes, {
3342
3369
  selectedItems: PropTypes__default["default"].array,
3343
3370
  initialSelectedItems: PropTypes__default["default"].array,
@@ -3527,7 +3554,7 @@ function useMultipleSelection(userProps) {
3527
3554
  keyNavigationPrevious = props.keyNavigationPrevious;
3528
3555
 
3529
3556
  // Reducer init.
3530
- var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState),
3557
+ var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState, isStateEqual),
3531
3558
  state = _useControlledReducer[0],
3532
3559
  dispatch = _useControlledReducer[1];
3533
3560
  var activeIndex = state.activeIndex,
@@ -1692,9 +1692,10 @@ function useLatestRef(val) {
1692
1692
  * @param {Function} reducer Reducer function from downshift.
1693
1693
  * @param {Object} props The hook props, also passed to createInitialState.
1694
1694
  * @param {Function} createInitialState Function that returns the initial state.
1695
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1695
1696
  * @returns {Array} An array with the state and an action dispatcher.
1696
1697
  */
1697
- function useEnhancedReducer(reducer, props, createInitialState) {
1698
+ function useEnhancedReducer(reducer, props, createInitialState, isStateEqual) {
1698
1699
  var prevStateRef = React.useRef();
1699
1700
  var actionRef = React.useRef();
1700
1701
  var enhancedReducer = React.useCallback(function (state, action) {
@@ -1717,11 +1718,12 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1717
1718
  }, [propsRef]);
1718
1719
  var action = actionRef.current;
1719
1720
  React.useEffect(function () {
1720
- if (action && prevStateRef.current && prevStateRef.current !== state) {
1721
+ var stateChanged = prevStateRef.current && !isStateEqual(prevStateRef.current, state);
1722
+ if (action && stateChanged) {
1721
1723
  callOnChangeProps(action, getState(prevStateRef.current, action.props), state);
1722
1724
  }
1723
1725
  prevStateRef.current = state;
1724
- }, [state, props, action]);
1726
+ }, [state, props, action, isStateEqual]);
1725
1727
  return [state, dispatchWithProps];
1726
1728
  }
1727
1729
 
@@ -1732,10 +1734,11 @@ function useEnhancedReducer(reducer, props, createInitialState) {
1732
1734
  * @param {Function} reducer Reducer function from downshift.
1733
1735
  * @param {Object} props The hook props, also passed to createInitialState.
1734
1736
  * @param {Function} createInitialState Function that returns the initial state.
1737
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
1735
1738
  * @returns {Array} An array with the state and an action dispatcher.
1736
1739
  */
1737
- function useControlledReducer$1(reducer, props, createInitialState) {
1738
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
1740
+ function useControlledReducer$1(reducer, props, createInitialState, isStateEqual) {
1741
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
1739
1742
  state = _useEnhancedReducer[0],
1740
1743
  dispatch = _useEnhancedReducer[1];
1741
1744
  return [getState(state, props), dispatch];
@@ -2017,6 +2020,18 @@ function getChangesOnSelection(props, highlightedIndex, inputValue) {
2017
2020
  }));
2018
2021
  }
2019
2022
 
2023
+ /**
2024
+ * Check if a state is equal for dropdowns, by comparing isOpen, inputValue, highlightedIndex and selected item.
2025
+ * Used by useSelect and useCombobox.
2026
+ *
2027
+ * @param {Object} prevState
2028
+ * @param {Object} newState
2029
+ * @returns {boolean} Wheather the states are deeply equal.
2030
+ */
2031
+ function isDropdownsStateEqual(prevState, newState) {
2032
+ return prevState.isOpen === newState.isOpen && prevState.inputValue === newState.inputValue && prevState.highlightedIndex === newState.highlightedIndex && prevState.selectedItem === newState.selectedItem;
2033
+ }
2034
+
2020
2035
  // Shared between all exports.
2021
2036
  var commonPropTypes = {
2022
2037
  environment: PropTypes__default["default"].shape({
@@ -2339,14 +2354,13 @@ function useSelect(userProps) {
2339
2354
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2340
2355
  getA11yStatusMessage = props.getA11yStatusMessage;
2341
2356
  // Initial state depending on controlled props.
2342
- var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2),
2357
+ var _useControlledReducer = useControlledReducer$1(downshiftSelectReducer, props, getInitialState$2, isDropdownsStateEqual),
2343
2358
  state = _useControlledReducer[0],
2344
2359
  dispatch = _useControlledReducer[1];
2345
2360
  var isOpen = state.isOpen,
2346
2361
  highlightedIndex = state.highlightedIndex,
2347
2362
  selectedItem = state.selectedItem,
2348
2363
  inputValue = state.inputValue;
2349
-
2350
2364
  // Element efs.
2351
2365
  var toggleButtonRef = React.useRef(null);
2352
2366
  var menuRef = React.useRef(null);
@@ -2812,11 +2826,12 @@ var propTypes$1 = _extends__default["default"]({}, commonDropdownPropTypes, {
2812
2826
  * @param {Function} reducer Reducer function from downshift.
2813
2827
  * @param {Object} props The hook props, also passed to createInitialState.
2814
2828
  * @param {Function} createInitialState Function that returns the initial state.
2829
+ * @param {Function} isStateEqual Function that checks if a previous state is equal to the next.
2815
2830
  * @returns {Array} An array with the state and an action dispatcher.
2816
2831
  */
2817
- function useControlledReducer(reducer, props, createInitialState) {
2832
+ function useControlledReducer(reducer, props, createInitialState, isStateEqual) {
2818
2833
  var previousSelectedItemRef = React.useRef();
2819
- var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState),
2834
+ var _useEnhancedReducer = useEnhancedReducer(reducer, props, createInitialState, isStateEqual),
2820
2835
  state = _useEnhancedReducer[0],
2821
2836
  dispatch = _useEnhancedReducer[1];
2822
2837
 
@@ -2990,7 +3005,7 @@ function useCombobox(userProps) {
2990
3005
  getA11ySelectionMessage = props.getA11ySelectionMessage,
2991
3006
  itemToString = props.itemToString;
2992
3007
  // Initial state depending on controlled props.
2993
- var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1),
3008
+ var _useControlledReducer = useControlledReducer(downshiftUseComboboxReducer, props, getInitialState$1, isDropdownsStateEqual),
2994
3009
  state = _useControlledReducer[0],
2995
3010
  dispatch = _useControlledReducer[1];
2996
3011
  var isOpen = state.isOpen,
@@ -3475,6 +3490,18 @@ function getA11yRemovalMessage(selectionParameters) {
3475
3490
  itemToStringLocal = selectionParameters.itemToString;
3476
3491
  return itemToStringLocal(removedSelectedItem) + " has been removed.";
3477
3492
  }
3493
+
3494
+ /**
3495
+ * Check if a state is equal for taglist, by comparing active index and selected items.
3496
+ * Used by useSelect and useCombobox.
3497
+ *
3498
+ * @param {Object} prevState
3499
+ * @param {Object} newState
3500
+ * @returns {boolean} Wheather the states are deeply equal.
3501
+ */
3502
+ function isStateEqual(prevState, newState) {
3503
+ return prevState.selectedItems === newState.selectedItems && prevState.activeIndex === newState.activeIndex;
3504
+ }
3478
3505
  var propTypes = _extends__default["default"]({}, commonPropTypes, {
3479
3506
  selectedItems: PropTypes__default["default"].array,
3480
3507
  initialSelectedItems: PropTypes__default["default"].array,
@@ -3664,7 +3691,7 @@ function useMultipleSelection(userProps) {
3664
3691
  keyNavigationPrevious = props.keyNavigationPrevious;
3665
3692
 
3666
3693
  // Reducer init.
3667
- var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState),
3694
+ var _useControlledReducer = useControlledReducer$1(downshiftMultipleSelectionReducer, props, getInitialState, isStateEqual),
3668
3695
  state = _useControlledReducer[0],
3669
3696
  dispatch = _useControlledReducer[1];
3670
3697
  var activeIndex = state.activeIndex,