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.

Scroll jank when prepending async relay pagination data

See original GitHub issue

Hi! Great work on this library - really appreciate the standard support for inverse (chat) style scrolling. I have run in to a small issue when prepending data that comes from an asynchronous source that I believe draws from the small delay between when the data is appended and when firstItemIndex is changed and I was wondering if you had any suggestions?

For example, here’s a video of the jank I am experiencing: https://streamable.com/x1q88p

You’ll notice at around the 0:02 second mark there is some jitter as the data has been loaded but the start index has not been updated just yet. That animation jitter you see is actually the new data that was loaded before the scroll is pushed back down to where it should be by the firstItemIndex. The code to merge new data into the existing data array handled by Apollo is kind of long which is where I think the problem stems from as I explain below. Is there a way to update both the data and the firstItemIndex at the same time?

Here’s my code, I am using Apollo Server relay style pagination (edges and nodes). FETCH_ITEM_COUNT is a constant that is set to 20:

<Virtuoso
    firstItemIndex={firstItemIndex}
    initialTopMostItemIndex={FETCH_ITEM_COUNT - 1}
    data={data?.artistMessages?.edges || []}
    startReached={fetch}
    itemContent={(index, message) => {
    return (
        message?.node && (
        <ChatMessage message={message.node} key={index} />
        )
    );
    }}
/>

I took influence from your prepending example and used useState to initialize a firstItemIndex like so:

const [firstItemIndex, setFirstItemIndex] = useState(START_INDEX);

Where START_INDEX is a constant set to an arbitrarily large value: 1,000,000.

When start is reached, I have a fetch method to that loads the next batch of data (cursor based pagination) like so:

const fetch = useCallback(
async (index: number) => {
    // check to confirm that there is data to query for before running the fetch
    if (fetchMore && data?.artistMessages?.pageInfo.hasPreviousPage) {
    const items = await fetchMore({
        variables: {
            last: FETCH_ITEM_COUNT,
            before: data.artistMessages?.pageInfo.startCursor,
            artistId: parseInt(artistId),
        },
    });
    // items contains the new elements, subtract the new items from the firstItemIndex
    setFirstItemIndex((curr) => {
        return curr - (items.data.artistMessages?.edges?.length || 0);
    });
    }
},
[data, fetchMore, artistId]
);

I call fetch and receive a new batch of data to prepend to my list. Notice how I do not have a useState for the data attribute of Virtuoso? This is because Apollo Server Relay pagination handles updating the data.artistMessages.edges internally. I’m thinking this is where the jank comes from since the code to prepend relay data is kind of lengthy see here. Apollo writes to client cache so that might be where the delay is coming from.

Now with the full scope of this issue, do you think it possible to be able to update the firstItemIndex and data at the same time? I may not fully understand the rendering process in React but I’m led to believe that having two points that need to be updated is causing the temporary misalignment of data on screen.

I thought I could utilize my datasource length to prevent needing a firstItemIndex state hook like so:

firstItemIndex={1000000 - (data?.artistMessages?.edges?.length || 0)}

However this results in an error on page load:

upwardScrollFixSystem.ts:93 Uncaught TypeError: Cannot read property ‘originalIndex’ of undefined

Let me know if there’s anything else I can provide!! Thanks 😃

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:16 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
seahorsepipcommented, Dec 28, 2020

@petyosi Window 10 (latest insider slow ring) with latest stable Chrome. It’s a 4k screen running most of the time on the intel integrated GPU so performance is a bit more limited unless I force the Nvidia GPU 😅.

0reactions
seahorsepipcommented, Dec 28, 2020

@petyosi Also keep in mind that there might be still scroll events emitted when the end is reached due to inertia from most touchpad drivers that might shift the scroll between measure and scroll compensation.

Never mind, also happens when I scroll with a mouse which doesn’t have inertia.

Read more comments on GitHub >

github_iconTop Results From Across the Web

merge previous data while scrolling on relay pagination graphql
I am trying to use relay style pagination. However, I am getting trouble on infinite scrolling. When i scroll or load next sets...
Read more >
Paginating Requests in APIs (2020) - Hacker News
When I worked for a news site, we moved all listing endpoints from offset to timestamp based pagination because offset based pagination assumes...
Read more >
Pagination and infinite scroll with React Query v3
Learn how to implement pagination and infinite scroll using React Query, a popular React library for state management.
Read more >
Ext.toolbar.Paging | Ext JS 6.2.0 - Sencha Documentation
Paging is used to reduce the amount of data exchanged with the client. Note: if there are more records/rows than can be viewed...
Read more >
Effortless Pagination with GraphQL and Relay? Really!
It's the year 2020. You use a modern front-end stack of Relay, GraphQL, React and TypeScript. You can build an infinite scroll 'feed'...
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