Scrollable Grid with Just-in-Time Data Loading – Part 2: Storing and Restoring Scroll Position with React Window

On my current project, we’re using just-in-time loading on a grid that might render up to twenty thousand rows. Each of these rows represents a product and is clickable.

On row click, the user is redirected to another page (a product detail page). A user might want to check out these product details and then navigate back to the product table. On returning to the table, it would be annoying if they lost their scroll position and had to scroll all the way down to their previous location. It would be much better if they were navigated to their previous scroll location on table load.

(In the first post of this series, I went over how to fetch data in batches with React Window’s InfiniteLoader and render the data in windowed chunks with react-window. Data being fetched and rendered incrementally means a shorter initial load time and a better user experience.)

To restore the user to their previous scroll location:

  1. Create a bit of state storing the user’s most recent scroll location.
  2. Navigate the user to their most recent scroll location on table load.

1. Store Scroll Location in State

In our application, we stored the scroll state in Apollo Client local state. For the purposes of this demo, let’s say you are using the Grid react window UI component and that the scroll state is stored in the Grid’s parent component.

The initial Grid scroll state would be zero for both the row and column index, like this:

const [scrollState, setScrollState] = React.useState({
rowIndex: 0,
columnIndex: 0
})

The row index and column index should be updated whenever the user scrolls to a new spot in the grid. How do you know when the user has navigated to a new section? React-table’s onItemsRendered callback is called whenever the user scrolls to a new section. The callback gets invoked with information about the section of the grid that was rendered.  You just need to store the relevant information — the visibleRowStartIndex and the visibleColumnIndex — in the scroll state:

onItemsRendered={({
visibleRowStartIndex,
visibleColumnStartIndex,
visibleRowStopIndex,
overscanRowStopIndex,
overscanRowStartIndex,
}) => {
props.setScrollRowAndColumn(visibleRowStartIndex, visibleColumnStartIndex)
// other relevant functions
}}

2. Navigate User to Previous Scroll Location on Table Load

Now that you are storing the scroll state, you can use the row index and column index in scroll state to restore the previous scroll location when rendering the table. React window’s Grid component has the properties initialScrollTop to set the vertical offset and initialScrollLeft to set the horizontal offset on initial render. For lists, since the user can only scroll on one access, there is only one property to set (initialScrollOffset).

The initial scroll top/scroll left takes an offset. To calculate the initial scroll top from the row index, multiply the row height by the row index. Similarly, to calculate the initial scroll left, multiply the column width by the column index.

Demo

Checkout the demo on code sandbox or github.


This is the second post in a series on creating a scrollable grid with just-in-time data loading:

  1. Using React Window
  2. Storing and Restoring Scroll Position with React Window
  3. Using React Table with React Window
  4. Back-End Implementation (Coming Soon)