React-window: How to use scrollToItem with InfiniteLoader?

Created on 5 May 2020  路  7Comments  路  Source: bvaughn/react-window

Hi,

I'm a little confused about how to call scrollToItem() when the VariableSizedList is within an InfiniteLoader tag. My understanding is that you would use createRef() to assign a new ref to the list, but there is already a ref getting passed down. I've tried running scrollToItem on this latter ref, but it doesn't work:

````
return (
isItemLoaded={isItemLoaded}
itemCount={itemCount}
loadMoreItems={loadMoreItems}
>
{({ onItemsRendered, ref }) => {
if (scrollTargetBlockIndex>0) {
ref.current.scrollToItem(scrollTargetBlockIndex);
scrollToConsumerSuccess();
};
return (

{
({height, width}) => (
height={height}
width={width}
itemCount={consumerBlocks.length}
itemSize={getItemSize}
onItemsRendered={onItemsRendered}
ref={ref}
overscanCount={4}
minimumBatchSize={20}
>
{Row}

)
}

)}}

);

````
The key line is

ref.current.scrollToItem(scrollTargetBlockIndex);

How should I do this? Is it possible?

Thank you in advance.

Simon

Most helpful comment

@manacoa I just dealt with something like this myself.

What worked for me was

const Component = () => {
    // bunch of code 
    const virtualLoaderRef = useRef(null);

    const customHandleScroll = ({ visibleStartIndex }) => {
        if (// logic for whether to trigger scroll) {
             virtualLoaderRef.current._listRef.scrollToItem(indexYouWantToScrollTo)
        }
     }

   return (
      <InfiniteLoader
        ref={virtualLoaderRef}
        isItemLoaded={isItemLoaded}
        itemCount={totalCount} 
        loadMoreItems={loadMoreItems}
        threshold={threshold}
      >
        {({ onItemsRendered, ref }) => (
          <VariableSizeList
            onItemsRendered={({
              overscanStartIndex,
              overscanStopIndex,
              visibleStartIndex,
              visibleStopIndex
            }) => {
              onItemsRendered({
                overscanStartIndex,
                overscanStopIndex,
                visibleStartIndex,
                visibleStopIndex
              });
              customHandleScroll({ visibleStartIndex });
            }}
            ref={ref}
            height={800}
            itemCount={totalCount}
            itemSize={getItemSize}
            itemData={itemData}
            width={300}
            itemKey={itemKey}
          >
            {Row}
          </VariableSizeList>
        )}
      </InfiniteLoader>
  )
}

key line being virtualLoaderRef.current._listRef.scrollToItem(indexYouWantToScrollTo) in conjunction with setting the ref on InfiniteLoader

Hope that's helpful

All 7 comments

@manacoa I just dealt with something like this myself.

What worked for me was

const Component = () => {
    // bunch of code 
    const virtualLoaderRef = useRef(null);

    const customHandleScroll = ({ visibleStartIndex }) => {
        if (// logic for whether to trigger scroll) {
             virtualLoaderRef.current._listRef.scrollToItem(indexYouWantToScrollTo)
        }
     }

   return (
      <InfiniteLoader
        ref={virtualLoaderRef}
        isItemLoaded={isItemLoaded}
        itemCount={totalCount} 
        loadMoreItems={loadMoreItems}
        threshold={threshold}
      >
        {({ onItemsRendered, ref }) => (
          <VariableSizeList
            onItemsRendered={({
              overscanStartIndex,
              overscanStopIndex,
              visibleStartIndex,
              visibleStopIndex
            }) => {
              onItemsRendered({
                overscanStartIndex,
                overscanStopIndex,
                visibleStartIndex,
                visibleStopIndex
              });
              customHandleScroll({ visibleStartIndex });
            }}
            ref={ref}
            height={800}
            itemCount={totalCount}
            itemSize={getItemSize}
            itemData={itemData}
            width={300}
            itemKey={itemKey}
          >
            {Row}
          </VariableSizeList>
        )}
      </InfiniteLoader>
  )
}

key line being virtualLoaderRef.current._listRef.scrollToItem(indexYouWantToScrollTo) in conjunction with setting the ref on InfiniteLoader

Hope that's helpful

I had to dig the virtualLoaderRef.current._listRef.scrollToItem... as well, wouldn't it be better for InfiniteLoader to expose _listRef in the API? we have no guarantee _listRef to be accessible and not renamed in future releases.

Thanks to both of you! It worked a treat!

It would be nice if _listRef was exposed publicly.

@bvaughn had an alternative suggestion here: https://github.com/bvaughn/react-window/issues/324#issuecomment-528887341

His proposed solution doesn't work for me, however, as it results in a whole bunch of typescript errors, so I'll use _listRef for now.

It would be nice if _listRef was exposed publicly.

@bvaughn had an alternative suggestion here: #324 (comment)

His proposed solution doesn't work for me, however, as it results in a whole bunch of typescript errors, so I'll use _listRef for now.

Thanks for pointing that approach out @johnnyoshika - it feels much better than having nested refs and works the same for me. No typescript, so I did not experience any issues.

My case for program scrolling:

https://github.com/bvaughn/react-window/issues/324#issuecomment-664483174

About solution from this link: https://github.com/bvaughn/react-window/issues/324#issuecomment-528887341

ref={list => {
  ref(list); // Give InfiniteLoader a reference to the list
  this.listRef.current = ref; // Set your own ref to it as well.
}}

My case:
Instead of the this.listRef.current = ref; i'm wrote this.listRef.current = list;

_InfntLdrHOC.tsx_

import InfiniteLoader from 'react-window-infinite-loader';
...
<InfiniteLoader
  isItemLoaded={isItemLoaded}
  loadMoreItems={onScroll}
  itemCount={listCount}
>
  {({ onItemsRendered, ref }) => {
    return (
      <ListOfMessages
        config={{
          messages,
          height,
          width,
          ref,
          onItemsRendered,
          isFetchingNewScenario,
        }}
      />
    );
  }}
</InfiniteLoader>

_ListOfMessages.tsx_

import React from 'react';
import { VariableSizeList as List } from 'react-window';

import Message from '../Message';

class ListOfMessagesClass extends React.Component<any> {
  private listRef = React.createRef<any>();


  componentDidUpdate(prevProps: any) {
    const {
      isFetchingNewScenario: isFetchingNewScenarioPrev,
    } = prevProps.config;
    // eslint-disable-next-line react/destructuring-assignment
    const { isFetchingNewScenario } = this.props.config;

    if (isFetchingNewScenarioPrev && !isFetchingNewScenario) {
      this.scrollToNewMessage();
    }
  }

  scrollToNewMessage = () => {
    this.listRef.current!.scrollToItem(0);
  };

  render() {
    const { config } = this.props;
    const {
      messages = [],
      listCount,
      height,
      width,
      ref,
      onItemsRendered,
    } = config;

    const listLength = messages.length;

    return (
      <>
        <List
          height={height}
          itemCount={listLength}
          itemSize={(index: any) => messages[index].messageRenderHeight}
          width={width}
          ref={list => {
            ref(list); // Give InfiniteLoader a reference to the list
            // @ts-ignore
            this.listRef.current = list; // Set your own ref to it as well.
          }}
          onItemsRendered={onItemsRendered}
          itemData={messages}
          outerRef={this.outerRef}
        >
          {Message}
        </List>
      </>
    );
  }
}

export default ListOfMessages;

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vinnymac picture vinnymac  路  3Comments

bnikom picture bnikom  路  3Comments

carolin913 picture carolin913  路  3Comments

ajayns picture ajayns  路  3Comments

lifeisaloha picture lifeisaloha  路  3Comments