React-Window is a React library by Brian Vaughn for rendering a massive amount of items in a list (or a grid but I will use “list” to keep the sentences simple as principle is the same for both) efficiently.
By rendering only visible items
But the problem is that when you click on an item in a list, you can’t scroll up/down using keys.
such as Page Up/Down, Arrow Up/Down, Home, or End keys.
Let’s see how we can support scrolling in react-window with Page Up/Down.
Replicating the issue
Go to an (any example) react-window example and scroll up/down with keyboard without selecting an item in the list.
You should be able to scroll with any keys.
And then click on any item in the list and try to scroll with keyboard.
And you will see that it will move just once and stop responding.
outerListRef is an outerRef refers to the List itself (the container property) while innerListRef is the dynamic container which updates as you scroll and contains the maximum content height.
You can refer to the documentation on inner/outerRefs but found it a bit hard to grasp without looking at the code. So let’s take a look at what those two references actually refer to in rendered HTML.
The outerRef is the element we need to use scrollTo (scroll is the same)API with and the innerRef is the element we need to extract the maximum height from.
Without innerRef, you refer to it as outerRef.current.firstElementChild so innerRef improves readability.
Handling onKeyDown event
Let’s add the onKeyDown event handler, which is fired whenever you hold down any keys.
handleKeyDown is given a keyboard event with a keyCode property, which is destructured from the argument. And when the matching key is found from the keys then we set the scroll offset (where we are currently in the list).
keys object(an essentially a map) holds a list of keys to be handled where
pageUp has keyCode value of 33
pageDown has keyCode value of 34
end has keyCode value of 36
home has keyCode value of 35
So whenever pageUp/Down, end, or home keys are pressed, we are updating the current position (scroll offset).
maxHeight is retrieved using the innerRef‘s style height for convenience without using outerRef.
minHeight is set to oddly 0.1 instead of 0. I really have no idea why setting it to 0 would not work with scroll API.
Would anyone let me know why it is so?
And let’s rock and scroll~
As react-window mutates the DOM while scrolling, we need to add it to the useLayoutEffect because we need to scrolling to happen after it.
useLayoutEffect documentation says “it fires synchronously after all DOM mutations.”
Would anyone let me know if it’s a good approach? (because useEffect still worked fine.)