question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Append to window scroll

See original GitHub issue

It is a pleasure writing an issue in such a great project!

I was wondering, if leaving the height and width properties on their own (https://codesandbox.io/s/empty-breeze-jzbry?file=/src/App.js:595-649) is the best option to make scrollable element of list snap to window scrollbar. It seems a little buggy. Do we have an option to make virtualized element snap its scrollbar to main browser scrollbar?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:3
  • Comments:14 (6 by maintainers)

github_iconTop GitHub Comments

6reactions
vpcvdccommented, Jul 31, 2020

My solution for true virtual concept in window scroll - sample live code

  • window scroll (without virtual concept)
const parentRef = React.useRef(window.document.body);

const rowVirtualizer = useVirtual({
  size: 10000,
  parentRef,
  estimateSize: React.useCallback(() => 35, []),
  overscan: 5
});
  • window scroll (with virtual concept)
const parentRef = React.useRef(window.document.body);

const rowVirtualizer = useVirtual({
  size: 10000,
  parentRef,
  estimateSize: React.useCallback(() => 35, []),
  overscan: 5
});

const { scrollToOffset } = rowVirtualizer;
React.useEffect(() => {
  const resizeHandler = () => (window.document.body.style.height = `${window.innerHeight}px`);
  const scrollHandler = () => scrollToOffset(window.scrollY);
  window.addEventListener("resize", resizeHandler);
  window.addEventListener("scroll", scrollHandler, { passive: true });
  window.document.body.style.height = `${window.innerHeight}px`;
  scrollToOffset(window.scrollY);
  return () => {
    window.removeEventListener("resize", resizeHandler);
    window.removeEventListener("scroll", scrollHandler, { passive: true });
  };
}, [scrollToOffset]);

@tannerlinsley Thank you for such a great library

4reactions
mogelbrodcommented, Aug 27, 2020

I currently use this wrapping hook, compatible with the current release (v2.2.5):

import React from 'react'
import { useVirtual } from 'react-virtual'

export function useVirtualWindow(options) {
  const sizeKey = options.horizontal ? 'width' : 'height'

  const virtualizedRef = options.parentRef
  const virtualizedBounds = React.useRef()

  const scrollListenerRef = React.useRef()
  // Mock the API surface currently used through parentRef
  const mockedParentRef = React.useRef({
    get scrollLeft() {
      return window.scrollX - virtualizedBounds.current.left
    },
    get scrollTop() {
      return window.scrollY - virtualizedBounds.current.top
    },
    getBoundingClientRect: () => ({
      width: window.innerWidth,
      height: window.innerHeight,
    }),
    addEventListener: (type, listener, ...args) => {
      // Only proxy 'scroll' event listeners
      if (type === 'scroll') {
        const proxiedListener = listener
        listener = scrollListenerRef.current = (originalEvent) => {
          // Some "scroll locking" implementations (such as for modals) work by
          // applying styling to the body. This optional offset will compensate
          // for that.
          const bodyOffset = parseInt(document.body.style.top || '0', 10)

          const target = {
            scrollLeft: window.scrollX - virtualizedBounds.current.left,
            scrollTop: window.scrollY - virtualizedBounds.current.top - bodyOffset,
          }
          proxiedListener({ target })
        }
        listener()
      }
      return document.addEventListener(type, listener, ...args)
    },
    removeEventListener: (type, listener, ...args) => {
      if (type === 'scroll') {
        listener = scrollListenerRef.current
      }
      return document.removeEventListener(type, listener, ...args)
    }
  })

  // Track dimensions of the virtualized container
  React.useLayoutEffect(() => {
    const onResize = () => {
      const rect = virtualizedRef.current.getBoundingClientRect()
      virtualizedBounds.current = {
        left: rect.left + window.scrollX,
        top: rect.top + window.scrollY,
      }
    }
    onResize()
    window.addEventListener('resize', onResize)
    return () => {
      window.removeEventListener('resize', onResize)
    }
  }, [virtualizedRef, sizeKey])

  return useVirtual({
    ...options,
    parentRef: mockedParentRef,
  })
}

Usage is just like the regular useVirtual() (provide the scrolled list as parentRef).

As you can see it has to mock the parentRef to intercept bounds checking and the scroll event. Ideally some variation of the version provided by @petersendidit above would avoid these ugly hacks, while not messing with the API surface too much for the sake of a single use case.

Read more comments on GitHub >

github_iconTop Results From Across the Web

When window scroll, I want to append a div and hide the div ...
I want to create a function, when user scroll down to the middle, the menu will have a class 'sticky', when the div...
Read more >
Window.scroll() - Web APIs - MDN Web Docs
The Window.scroll() method scrolls the window to a particular place in ... Specifies the number of pixels along the Y axis to scroll...
Read more >
Append to window scroll · Issue #14 · TanStack/virtual - GitHub
My solution for true virtual concept in window scroll - sample live code. window scroll (without virtual concept). const parentRef = React.
Read more >
.scroll() | jQuery API Documentation
The scroll event is sent to an element when the user scrolls to a different place in the element. It applies to window...
Read more >
Window sizes and scrolling - The Modern JavaScript Tutorial
How do we get the full width and height of the document, including the scrolled out part? How do we scroll the page...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found