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

`measureLayout` relative to `ScrollView` returns incorrect `y` value

Open nandorojo opened this issue 4 years ago • 3 comments

The problem

Calling measureLayout relative to a ScrollView returns the incorrect y value when the scroll position is greater than 0.

How to reproduce

Simplified test case: https://codesandbox.io/s/lucid-sea-rq0ny?file=/src/App.js:0-1339

Steps to reproduce:

  1. Click on a number in the reproduction. This should scroll to it.
  2. Look in the console. It outputs the location it should scroll to vs the result of measureLayout.
  3. Notice that the y value returned from measureLayout is incorrectly subtracting the current scroll position.

To reproduce on your own:

  1. Add a ScrollView, pass it a ref: scrollRef
  2. Add a text inside of the ScrollView, give it a ref: textRef. Put the text far down, maybe give it like marginTop: 600.
  3. Scroll down a bit.
  4. Call textRef.current.measureLayout(scrollRef.current, callback) and log the resulting y value from the callback.
  5. Notice that it does not give you the distance from the top of the scrollable content; rather, it gives you the distance from the top of the ScrollView, minus the scroll position.

Expected behavior

The behavior should match that of native. Try the example on iOS here, and notice that it always scrolls to the correct spot: https://snack.expo.dev/@beatgig/dedc14

On native, calling measureLayout relative to a ScrollView gives the y coordinate relative to the top of the the scrollable content, regardless of scroll position.

Environment (include versions). Did this work in previous versions?

  • React Native for Web (version): 0.17.0
  • React (version): 17.0.2
  • Browser: Chrome

It doesn't work in any previous versions, tried back to 0.15.x, where measureLayout was initially implemented for ScrollViews (#1957).

nandorojo avatar Aug 22 '21 00:08 nandorojo

In case anyone needs a temporary solution, you can use getInnerViewRef() if Platform.OS === 'web':

const scrollTo = (index) => () => {
    viewRefs.current[index].measureLayout(
-     scrollRef.current,
+     scrollRef.current.getInnerViewRef(),
      (x, y) => {
        scrollRef.current.scrollTo({
          y,
          animated: true
        });
      }
    );
  };

nandorojo avatar Aug 26 '21 00:08 nandorojo

I'll review a PR for this. Thanks

necolas avatar Sep 28 '21 17:09 necolas

For whatever reason I was looking at react-native-anchor today in combination with react-native-web and just wanted to note that this is apparently still an active issue requiring a patch to react-native-anchor in order to scroll reliably on web. I had a brief investigation into providing the needed PR here as there is not one in the PR queue yet, but don't quite have the domain knowledge in react-native-web to do so. Perhaps in the future. But it's an active / actively-worked-around issue at the moment, ready for a PR from you, dear reader, according to the comment above :-).

mikehardy avatar Nov 21 '21 14:11 mikehardy