Recyclerlistview: this._scrollViewRef.scrollTo is not a function

Created on 7 May 2018  路  15Comments  路  Source: Flipkart/recyclerlistview

The recyclerlistview performance is very good. But i am having a issue with the onEndReached props. After calling the onEndReached i am adding the new data to the DataProvider. But after the data is added i m getting error this._scrollViewRef.scrollTo is not a function

class NewsList extends React.Component {

constructor(props) {
    super(props);
this.dataProvider = new DataProvider((r1, r2) => {
                return r1 !== r2;
            }).cloneWithRows(this.props.list);
}

componentWillReceiveProps  ()  {   
   this.setState(prevState => ({
    dataProvider: prevState.dataProvider.cloneWithRows(this.props.list)
  }))   
  }

render() {     
 return (
  <View style={{flex:1}}>
<RecyclerListView
         ref={ref => {this.listRef = ref;}}
          contentContainerStyle={{paddingBottom:80}}
         externalScrollView={ExtendedScrollView}
         layoutProvider={this._layoutProvider}
         dataProvider={this.state.dataProvider}
         rowRenderer={this._rowRenderer} 
         onEndReached={() => this.props.handleLoadMore()}
         onEndReachedThreshold={0.3}
         renderFooter={this.renderFooter}
         animatedEvent={{nativeEvent: {contentOffset: {y: this.scroll}}}}
         renderAheadOffset={250}        
         refreshControl={
              <RefreshControl
              refreshing={this.state.refreshing}
              onRefresh={this._onRefresh.bind(this)} />
                  }
         /> 
    </View>    
    );
  }
}

screenshot_20180507-123302

All 15 comments

Looks like you haven't fully implemented BaseScrollView interface. That is necessary since you're using externalScrollView.
e.g,

class ExtendedScrollView extends BaseScrollView {
scrollTo(...args) {
      //Get this from your impl
      if(this._scrollViewRef) {
         this._scrollViewRef.scrollTo(...args);
      }
   }
 ....
}

Thanks for the quick response. My externalScrollView class is like below. Is it correct?

class ExtendedScrollView extends BaseScrollView {
    scrollTo(...args) {     
    if (this._scrollViewRef) { 
       this._scrollViewRef.scrollTo(...args);
    }
 }

  render() {
     return (
     <Animated.ScrollView {...this.props}
     ref={scrollView => {this._scrollViewRef = scrollView;}}
     scrollEventThrottle={1}
     onScroll={Animated.event([this.props.animatedEvent], {listener: this.props.onScroll,useNativeDriver: true})}
     />
     )}
}

Looks correct. Is it working fine now?

Please see the step below. The issue is in the 4th step.

  1. Enter into the listing page (10 items)
  2. At the end of list onEndReached called and new data appended to the list +10 items. (Working fine)
  3. We have now 20 items. Then navigate to a new page and come back to the listing page.
  4. It has 20 items. Then scroll to end onEndReached called and api sent response but no data appended to the list. Here I was getting the this._scrollViewRef.scrollTo is not a function error. Now the error is not showing but new data is also not appending. And it is producing extra space about 250px at the top of the list. (issue is in this step)

If I do not use externalScrollView then it is working fine. But I need to use externalScrollView to animate things.

I'll need a sample to look into it. I don't think this a RLV issue. Most likely there must be some bug in your code. You can try your externalScrollView in one of the samples to see if it works fine.

@naqvitalha can you provide a full example of how to use the scrollTo with externalScrollView? I'm trying to do this and it's not working. Should the below code work: https://snack.expo.io/r1IoPqEkm?

@rootedy-ffit did you found any solution for scrollTo please ?

try using .scrollToOffset(0,0,true)

Looks like you haven't fully implemented BaseScrollView interface. That is necessary since you're using externalScrollView.
e.g,

class ExtendedScrollView extends BaseScrollView {
scrollTo(...args) {
      //Get this from your impl
      if(this._scrollViewRef) {
         this._scrollViewRef.scrollTo(...args);
      }
   }
 ....
}

Since it is an Animated ScrollView you will have to use getNode() function on _scrollViewRef.

if(this._scrollViewRef) {
     this._scrollViewRef.getNode().scrollTo(...args);
}

This worked for me.

I ran into this error while using a higher-order component to wrap my ExtendedScrollView, like so:

export default withNavigation(ExtendedScrollView);

This made the scrollTo() defined in ExtendedScrollView inaccessible since the component exported is the wrapped component, not the original component. A solution is to move the wrapping to a child component.

Seems like the solution offered by @tanmaybhatt should work for the combination with Animated.ScrollView, so I think this issue can be closed.

I ran into this. the snack https://snack.expo.io/r1IoPqEkm throws the error and I use the same setup. What is the issue? Some typo? @naqvitalha @evert-smit

You're setting a ref called listView on your RecyclerListView:

render() {
    return <RecyclerListView 
    ref={ref => {this.listView = ref}}
    externalScrollView={ExternalScrollView}
    layoutProvider={this._layoutProvider}
    dataProvider={this.state.dataProvider}
    rowRenderer={this._rowRenderer} />;
 }

and then you're doing this:

componentDidMount() {
   setTimeout(()=>{
       this.listView.scrollTo({y: 300, animated: true});
   }, 5000);
}

This is not going to work because your RecycleTestComponent doesn't have a scrollTo method: that's the method that you're trying to access here.

It also won't work because you're not doing the scrolling on the component that should actually be scrolled: your ExternalScrollView.

So, you can move that scrollTo call to your ExternalScrollView component. You can get rid of setting the listView ref.

Thanks for your reply! @evert-smit, what I had imagined would be that the ref would be somehow magically passed on to the component but of course it would not be.

Reading your comment I did this 5min solution as I really need the ref to control it from some other UI components.

render() {
    return <RecyclerListView 
    setScrollViewRef={(ref) => this.scrollViewRef = ref}
    externalScrollView={ExternalScrollView}
    layoutProvider={this._layoutProvider}
    dataProvider={this.state.dataProvider}
    rowRenderer={this._rowRenderer} />;
 };

and setScrollViewRef will be passed on to the ExternalScrollView and you can do something like

componentDidMount(){
    this.props.setScrollViewRef(this._scrollViewRef)
  }

This worked for me:

const listView = useRef();

const scrollToTop = () => {
  listView.current?.scrollToOffset(0, 0, true);
};

<RecyclerListView ref={listView}...

Thank you, @msmfsd. It works fine!!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ardyfeb picture ardyfeb  路  6Comments

leifermendez picture leifermendez  路  8Comments

sksin28 picture sksin28  路  8Comments

ErHarinderSingh picture ErHarinderSingh  路  6Comments

VilleKokkarinen picture VilleKokkarinen  路  6Comments