https://github.com/varugasu/cracked-frontend
https://github.com/varugasu/cracked-frontend
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/varugasu/cracked-frontend
- Owner: varugasu
- Created: 2025-09-06T13:46:13.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2025-09-06T13:46:16.000Z (4 months ago)
- Last Synced: 2025-09-27T04:30:58.759Z (4 months ago)
- Language: TypeScript
- Size: 171 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Virtualization
## Fixed-Height
The core of this strategy is the `slice`, where we only render what is **inside of the viewport**. That's why we need a predictable way of determining how many items we should render that is a **fixed height per item**
That's why we need **three layers**:
The **Viewport** is a **fixed-height container**:
- It defines how much the list we will see (`viewportHeight`)
- How far the user has scrolled (`scrollTop`)
- and hides the full height of the list (Spacer)
The **Spacer** fakes the full list height, therefore its height is `itemHeight * items.length`. It will give the scrollbar the correct range so the browser thinks **the whole list is rendered**. This provides affordance to the user so they can keep scrolling.
Finally, we have the **Slice** that will the items but it will also **show the user how much they have scrolled** by using the `offsetY`. This will move the scroll to correctly show the position we are at the list.
For the Slice, we render `visibleCount + overscan * 2` items. The visible count is defined by `viewportHeight / itemHeight`. The `overscan`is a buffer to render extra rows **outside of the visible viewport**. This will ensure that even if we scroll really fast, we will still show the next items, providing a **smooth scrolling experience to the user**.
We use `overscan * 2` to ensure we are rendering **before and after**, in case the user also decides to scroll back really fast. Therefore, `* 2` ensuress **overscan above \* overscan below**
Finally, we have the slice that is indeed what we are rendering. We get the `items` and run `.slice` with two indexes we calculated:
```ts
const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan)
const end = Math.min(items.length - 1, start + visibleCount + overscan * 2)
```
For `start`, `scrollTop / itemHeight` defines **how many rows** have been scrolled past.
If `scrollTop = 4800` and `itemHeight = 48`, then we know that **100** have been scrolled past.
The `Math.floor` rounds down the start in case we are between rows and `- overscan` ensures we render a few extra rows **above** the viewport
`end` is more straightforward. Given the `start`, we add the amount of visible rows we want (`visibleCount`) and `overscan * 2`. This is multiplied by two to covers the rows we skipped at the top and the buffer at the bottom