petyosi / react-virtuoso

The most powerful virtual list component for React
https://virtuoso.dev
MIT License
5.25k stars 301 forks source link

[BUG] Unexpected behavior with `initialScrollTop` when using `useWindowScroll` #776

Closed dylanwulf closed 2 years ago

dylanwulf commented 2 years ago

Thank you for the wonderful project! Best virtualization library for react I have found so far.

Describe the bug When using useWindowScroll and initialScrollTop, I expected window.scrollY to become equal to initialScrollTop. What actually happens is window.scrollY becomes equal to initialScrollTop plus the height of everything above the first list item.

Reproduction https://codesandbox.io/s/react-virtuoso-window-scrolling-with-initialscrolltop-1oo5x2?file=/App.js

To Reproduce Steps to reproduce the behavior:

  1. Open reproduction
  2. Observe that the entire 150px tall div was scrolled out of view even though initialScrollTop is only 1

Desktop:

petyosi commented 2 years ago

That's by design - the scrollTop is relative to the top of the list. If you want to achieve what you describe, just go with useEffect and window.scrollTo, should work.

dylanwulf commented 2 years ago

@petyosi I don't think that works: https://codesandbox.io/s/useeffect-window-scrollto-does-not-work-lyp8g0?file=/App.js It looks like the list is not big enough for the window to have a scrollbar by the time useEffect runs. I also tried useLayoutEffect but that didn't make a difference

petyosi commented 2 years ago

@dylanwulf true, the list takes a frame to initialize and expand the scroll. Something like this should work I guess. I don't know your use case though.

setTimeout(() => {
      window.scrollTo({ top: 500 });
    });
dylanwulf commented 2 years ago

@petyosi That seems to work, thank you!

dylanwulf commented 1 year ago

Hi @petyosi, sorry to revive this issue but we recently updated to React 18 and enabled concurrent mode, and your suggested solution of using setTimeout inside of useEffect no longer works. See here for reproduction: https://codesandbox.io/s/useeffect-window-scrollto-does-not-work-forked-f7tjoe?file=/App.js It will randomly sometimes work, but most of the time it does not work. Do you know of any other way to guarantee that our window.scrollTo() call will happen after the list rendered & created a scrollbar? Thank you for your time!

SahidMiller commented 1 year ago

@dylanwulf @petyosi Just wanted to mention for future reference that getState + restoreStateFrom seem to work fine restoring the exact position after unmounting while using useWindowScroll. My first intuition was to use initialScrollTop and scrollTo (window/virtuoso) but couldn't get it working the way I expected.

dylanwulf commented 1 year ago

@SahidMiller Thanks for the tip! I wound up going with a solution that uses ResizeObserver to wait for the scroll element to grow before attempting to scroll, but your solution is probably better!