react-native-wheely icon indicating copy to clipboard operation
react-native-wheely copied to clipboard

selectedIndex not working properly in iOS

Open evrrnv opened this issue 1 year ago • 7 comments

it's working fine in index 0, but when I set different index, it appears as the video shows

https://github.com/user-attachments/assets/202fedce-40f1-4ab8-9b81-a61287907956

evrrnv avatar Dec 22 '24 21:12 evrrnv

Yup, experiencing the same, it is selecting an in between index on initial render if we do not render index 0

kristof-kovacs avatar May 07 '25 14:05 kristof-kovacs

Try to change: const [scrollY] = useState(new Animated.Value(0));

into:

const [scrollY] = useState(new Animated.Value((selectedIndex ?? 0) * itemHeight));

inside WheelPicker.tsx

lorenc-tomasz avatar Jul 27 '25 20:07 lorenc-tomasz

I have the similar issue when switch to React Native hermes engine.

Possible Root Cause

I doubt it's because in WheelPicker.tsx, the useEffect for scrollToIndex finishes before animated attributes (e.g. scale) in WheelPickerItem.tsx ready.

https://github.com/erksch/react-native-wheely/blob/4a13bfbfded7a3041372098fc519bc19cca91e86/src/WheelPicker.tsx#L105-L114

https://github.com/erksch/react-native-wheely/blob/4a13bfbfded7a3041372098fc519bc19cca91e86/src/WheelPickerItem.tsx#L76-L94

Potential Solution

Therefore, I add a setTimeout in useEffect to put this method into microtask queue, which solves my problem.

Here is the patch:

diff --git a/lib/WheelPicker.js b/lib/WheelPicker.js
index 575325b00e392692a69016b0e66b08c57825b229..9171f6d218b927fb5cc1517cd4267a9fe42ec8f9 100644
--- a/lib/WheelPicker.js
+++ b/lib/WheelPicker.js
@@ -67,11 +67,15 @@ const WheelPicker = ({ selectedIndex, options, onChange, selectedIndicatorStyle
      * This ensures that what the user sees as selected in the picker always corresponds to the value state.
      */
     (0, react_1.useEffect)(() => {
-        var _a;
-        (_a = flatListRef.current) === null || _a === void 0 ? void 0 : _a.scrollToIndex({
-            index: selectedIndex,
-            animated: false,
-        });
+        var timer = setTimeout(() => {
+            var _a;
+            
+            (_a = flatListRef.current) === null || _a === void 0 ? void 0 : _a.scrollToIndex({
+                index: selectedIndex,
+                animated: false,
+            });
+        }, 0);
+        return () => clearTimeout(timer);
     }, [selectedIndex]);
     return (react_1.default.createElement(react_native_1.View, Object.assign({ style: [WheelPicker_styles_1.default.container, { height: containerHeight }, containerStyle] }, containerProps),
         react_1.default.createElement(react_native_1.View, { style: [

Result

Before After
Image Image

blue86321 avatar Aug 24 '25 09:08 blue86321

I initially used timer fix, but on some devices and cases it was not working at the end. I guess it can be combined with what I proposed. Nevertheless interesting case :)

lorenc-tomasz avatar Aug 24 '25 11:08 lorenc-tomasz

I initially used timer fix, but on some devices and cases it was not working at the end. I guess it can be combined with what I proposed. Nevertheless interesting case :)

@lorenc-tomasz sad to hear that :( I firstly tried your solution, but it does not work for my usecase.

I wrapped WheelPicker to make component easier to use. I init with 0 at first, then I use a useEffect to update it.

If I use your solution, which does not make any difference since it's initial value is 0. that's why I think from the useEffect part.

export default function MyWheelPicker({ value, ... }) {
  const [selectedIndex, setSelectedIndex] = useState(0);

  useEffect(() => {

    // get index by value...

    setSelectedIndex(index);
  }, [indexDataMap, value]);

  ...

  return (
    <WheelPicker
      selectedIndex={selectedIndex}
      ...
    />
  );
}

blue86321 avatar Aug 25 '25 07:08 blue86321

So it depends on the use case. Good to know.

lorenc-tomasz avatar Aug 25 '25 08:08 lorenc-tomasz

I don't have a solution yet, but I wanted to +1 on having this issue not only when loading the list but also when onChange is called. I've tried the solutions mentioned in here (and also this one), as well as trying to figure it out myself, but no success so far. I'll update the thread with a solution if I find one

Edit: The fix @lorenc-tomasz suggested solved the issue for me! Thanks

https://github.com/user-attachments/assets/65040d60-c085-49aa-b26d-f42211579815

enrickdaltro avatar Aug 29 '25 20:08 enrickdaltro