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 (
itemCount={itemCount}
loadMoreItems={loadMoreItems}
>
{({ onItemsRendered, ref }) => {
if (scrollTargetBlockIndex>0) {
ref.current.scrollToItem(scrollTargetBlockIndex);
scrollToConsumerSuccess();
};
return (
{
({height, width}) => (
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
@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
_listRefwas 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
_listReffor 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;
Most helpful comment
@manacoa I just dealt with something like this myself.
What worked for me was
key line being
virtualLoaderRef.current._listRef.scrollToItem(indexYouWantToScrollTo)in conjunction with setting the ref onInfiniteLoaderHope that's helpful