QnA

react-virtual

Q&A 정리: react-virtual

@tanstack/react-virtual의 useVirtualizer와 useWindowVirtualizer의 차이는?

둘 다 긴 목록을 효율적으로 보여주는 도구지만, 스크롤 기준이 다르다. useVirtualizer는 특정 HTML 요소(예: div 박스) 안에서 스크롤할 때 사용하고, useWindowVirtualizer는 브라우저 창 전체를 스크롤 영역으로 사용할 때 쓴다.

useVirtualizer: This function returns a standard Virtualizer instance configured to work with an HTML element as the scrollElement.

useWindowVirtualizer: This function returns a window-based Virtualizer instance configured to work with the window as the scrollElement.


React 19에서 @tanstack/react-virtual 사용 시 스크롤할 때 "flushSync was called from inside a lifecycle method" 경고가 발생한다. 원인과 해결 방법은?

React 19에서는 화면 갱신을 즉시 처리하는 내부 기능(flushSync)이 특정 시점에 호출되면 경고를 띄운다. 설정에서 useFlushSync: false로 바꾸면 React가 자연스럽게 업데이트를 묶어 처리하므로 경고가 사라진다.

Both useVirtualizer and useWindowVirtualizer accept a useFlushSync option that controls whether React's flushSync is used for synchronous updates.

Type: boolean Default: true

When true, the virtualizer will use flushSync from react-dom to ensure synchronous rendering during scroll events. This provides the most accurate scrolling behavior but may impact performance in some scenarios.

React 19 compatibility: In React 19, you may see the following console warning when scrolling:

"flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task."

Setting useFlushSync: false will eliminate this warning by allowing React to batch updates naturally.


useFlushSync를 false로 설정하면 어떤 trade-off가 있는가?

켜두면 스크롤할 때 화면이 즉각 반응해 정확하지만, 성능이 떨어질 수 있다. 끄면 성능은 좋아지지만 빠르게 스크롤할 때 살짝 지연이 느껴질 수 있다. 정밀한 스크롤이 덜 중요한 목록이나 저사양 기기에서는 끄는 것이 유리하다.

When true, the virtualizer will use flushSync from react-dom to ensure synchronous rendering during scroll events. This provides the most accurate scrolling behavior but may impact performance in some scenarios.

You may want to set useFlushSync: false in the following scenarios:

  • Performance optimization: If you experience performance issues with rapid scrolling on lower-end devices
  • Testing environments: When running tests that don't require synchronous DOM updates
  • Non-critical lists: When slight visual delays during scrolling are acceptable for better overall performance

@tanstack/virtual의 count 옵션은 무엇인가?

가상화할 전체 항목의 개수를 지정하는 옵션이다. 예를 들어 1만 개의 데이터가 있으면 count에 10000을 넣는다.

The total number of items to virtualize.


@tanstack/virtual의 estimateSize 옵션은 무엇인가?

각 항목의 예상 크기(높이 또는 너비)를 알려주는 함수다. 화면에 보이지 않는 항목의 위치를 미리 계산하기 위해 사용하며, 나중에 실제 측정값으로 대체할 수도 있다.

This function is passed the index of each item and should return the actual size (or estimated size if you will be dynamically measuring items with virtualItem.measureElement) for each item. This measurement should return either the width or height depending on the orientation of your virtualizer.


아이템 높이가 제각각인 리스트에서 estimateSize에 작은 값을 넣으면 어떤 문제가 생기는가?

예상 크기를 실제보다 작게 잡으면, 초기 위치 계산이 부정확해져 스크롤할 때 항목이 갑자기 밀리거나 점프하는 현상이 생길 수 있다. 그래서 넉넉하게 큰 값을 추정하는 것이 권장된다.

If you are dynamically measuring your elements, it's recommended to estimate the largest possible size (width/height, within comfort) of your items. This will help the virtualizer calculate more accurate initial positions.


@tanstack/virtual의 overscan 옵션은 무엇이며, 값을 높이면 어떤 trade-off가 있는가?

화면에 보이는 영역 위아래로 미리 그려둘 항목의 개수다. 값을 높이면 빠르게 스크롤해도 빈 화면이 덜 보이지만, 그만큼 더 많은 항목을 그려야 해서 렌더링 시간이 늘어난다.

The number of items to render above and below the visible area. Increasing this number will increase the amount of time it takes to render the virtualizer, but might decrease the likelihood of seeing slow-rendering blank items at the top and bottom of the virtualizer when scrolling. The default value is 1.


@tanstack/virtual의 getVirtualItems()는 무엇을 반환하는가?

현재 화면에 보여야 할 가상 항목들의 목록을 반환한다. 실제로 화면에 그릴 항목만 골라서 돌려주므로, 이 목록을 기반으로 렌더링하면 된다.

Returns the virtual items for the current state of the virtualizer.


@tanstack/virtual의 VirtualItem 객체는 어떤 정보를 담고 있으며, start와 size는 어떻게 사용하는가?

각 가상 항목의 위치와 크기 정보를 담고 있다. start는 스크롤 영역 안에서 해당 항목이 시작하는 픽셀 위치이고, size는 항목의 높이(또는 너비)다. 이 값들을 CSS에 적용하여 항목을 올바른 자리에 배치한다.

The VirtualItem object represents a single item returned by the virtualizer. It contains information you need to render the item in the coordinate space within your virtualizer's scrollElement and other helpful properties/functions.

start: The starting pixel offset for the item. This is usually mapped to a css property or transform like top/left or translateX/translateY.

size: The size of the item. This is usually mapped to a css property like width/height.


VirtualItem의 size는 언제 추정값이고 언제 실측값인가?

항목이 실제로 화면에 그려져 측정되기 전에는 estimateSize가 반환한 추정값이고, measureElement로 측정된 뒤에는 실제 크기로 바뀐다. 처음에는 어림짐작으로 배치하고, 화면에 나타나면 정확한 치수로 교정하는 방식이다.

Before an item is measured with the VirtualItem.measureElement method, this will be the estimated size returned from your estimateSize virtualizer option. After an item is measured (if you choose to measure it at all), this value will be the number returned by your measureElement virtualizer option (which by default is configured to measure elements with getBoundingClientRect()).


@tanstack/virtual의 getTotalSize()는 무엇을 반환하며, 동적 측정 시 어떻게 변하는가?

전체 목록의 총 크기(픽셀)를 반환한다. 항목들이 화면에 그려지면서 실제 크기로 측정되면, 총 크기도 점진적으로 업데이트된다. 스크롤바 크기를 정확하게 유지하는 데 사용된다.

Returns the total size in pixels for the virtualized items. This measurement will incrementally change if you choose to dynamically measure your elements as they are rendered.


@tanstack/virtual의 measureElement 옵션은 무엇이며, estimateSize와 어떤 관계인가?

항목이 실제로 화면에 그려졌을 때 진짜 크기를 측정하는 함수다. estimateSize가 "예상 키"라면 measureElement는 "실제 키 측정"에 해당한다. 이 함수를 제공하면 추정값이 실측값으로 교체되어 더 정확한 스크롤이 가능해진다.

This optional function is called when the virtualizer needs to dynamically measure the size (width or height) of an item. You can use instance.options.horizontal to determine if the width or height of the item should be measured.