Skip to content

Programmatically updated values get out of sync #121

@xenvi

Description

@xenvi

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch react-native-input-select@2.1.7 for the project I'm working on.

If I updated selectedValue programmatically after the initial mount, the selectedItems state in the dropdown would get out of sync and not display the new value. I've updated the code to replace a useEffect that wasn't actually keeping the values in sync. I've tested with single item dropdowns and now it correctly reads both programmatic and manual selections -> i do not have any multi-select dropdowns in my app so did not test that use case.

Here is the diff that solved my problem:

diff --git a/node_modules/react-native-input-select/src/index.tsx b/node_modules/react-native-input-select/src/index.tsx
index f58e303..d0dc102 100644
--- a/node_modules/react-native-input-select/src/index.tsx
+++ b/node_modules/react-native-input-select/src/index.tsx
@@ -22,6 +22,7 @@ import {
   extractPropertyFromArray,
   getSelectionsData,
   removeDisabledItems,
+  shallowArrayEqual,
 } from './utils';
 import {
   useSelectionHandler,
@@ -151,14 +152,18 @@ export const DropdownSelect = forwardRef<DropdownSelectHandle, DropdownProps>(
       autoCloseOnSelect,
     });
 
+    /**
+     * Keep selectedValue in sync with selectedItem(s)
+     */
     useEffect(() => {
-      isMultiple
-        ? setSelectedItems(selectedValue as TSelectedItem[])
-        : setSelectedItem(selectedValue as TSelectedItem);
-
-      // setSelectedItems already updates selectedValue, so omit it from dependency array to avoid infinite loop
-      // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [setSelectedItems, setSelectedItem, isMultiple, onValueChange]);
+      if (isMultiple) {
+        const next = (selectedValue as TSelectedItem[] | undefined) ?? []
+        setSelectedItems(prev => (shallowArrayEqual(prev, next) ? prev : next))
+      } else {
+        const next = (selectedValue as TSelectedItem | undefined) ?? (null as any)
+        setSelectedItem(prev => (Object.is(prev, next) ? prev : next))
+      }
+    }, [selectedValue, isMultiple, setSelectedItems, setSelectedItem])
 
     /*===========================================
      * List type
diff --git a/node_modules/react-native-input-select/src/utils/index.ts b/node_modules/react-native-input-select/src/utils/index.ts
index c4ea126..22d4911 100644
--- a/node_modules/react-native-input-select/src/utils/index.ts
+++ b/node_modules/react-native-input-select/src/utils/index.ts
@@ -100,3 +100,10 @@ export const extractTextStylesFromArray = (
   }
   return extractedStyles;
 };
+
+export const shallowArrayEqual = <T,>(a: T[] = [], b: T[] = []) => {
+  if (a === b) return true
+  if (a.length !== b.length) return false
+  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false
+  return true
+}
\ No newline at end of file

This issue body was partially generated by patch-package.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions