Hi, onEndReached in List is triggered on start of the list
"react-native": "0.41.2"
"react": "~15.4.0"
"native-base": "^2.0.9"
It should be excuted, only when the end of the list is reached or the height in pixels from the inside container of the listviews bottom, specified in https://facebook.github.io/react-native/docs/listview.html#onendreachedthreshold
It executed when list is loaded two times.
import React, {Component, PropTypes, AppRegistry } from 'react';
import {
StyleSheet,
Dimensions,
TextInput
} from 'react-native';
import {Dimensions, Container, Content, List, Grid, Row, Button, Icon, Header, Footer, FooterTab, Text } from 'native-base';
import VideoPlayer from './videoPlayer';
const deviceWidth = Dimensions.get('window').width;
const videoHeight = deviceWidth + 10;
const styleVars = {
container: {
backgroundColor: '#ffffff',
},
videoList: {
flex: 1,
flexDirection: 'row',
alignItems: 'stretch',
},
ListViewStyle: {
flex: 0,
width: deviceWidth,
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'stretch',
margin: 0,
padding: 0,
borderWidth: 2,
},
inputStyle: {
minWidth: 100,
alignSelf: 'stretch',
padding: 0,
margin: 0,
backgroundColor: 'transparent',
color: 'black',
textDecorationLine: 'none',
},
item: {
position: 'relative',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
elevation: 1,
flex: 1,
backgroundColor: 'transparent',
height: Dimensions.get('window').width,
}
};
const styles = StyleSheet.create(styleVars);
class App extends Component {
static propTypes = {
videos: PropTypes.array.isRequired,
hashtags: PropTypes.array,
};
constructor(props) {
super(props);
this.state = {
offsetVideosCount: 0,
dataSource: this.props.videos,
items: [
{ title: '1' },
{ title: '2' },
{ title: '3' },
{ title: '4' },
{ title: '5' },
{ title: '6' },
{ title: '7' },
{ title: '8' },
{ title: '9' },
{ title: '10' },
{ title: '11' },
{ title: '12' },
{ title: '13' },
{ title: '14' },
{ title: '15' },
{ title: '16' },
{ title: '17' },
{ title: '18' },
{ title: '19' },
],
};
}
renderRow(item, sectionID, rowID) {
return (
<View style={styles.video}>
<Text>{sectionID}-{rowID}</Text>
</View>
);
}
whatsOnScroll(e) {
const offsetVideosCountRound = Number(Math.round(e.nativeEvent.contentOffset.y / videoHeight));
const offsetVideosCountCeil = Number(Math.ceil(e.nativeEvent.contentOffset.y / videoHeight));
const offsetVideosCount = offsetVideosCountCeil === this.props.videos.length - 1
? this.props.videos.length - 1 : offsetVideosCountRound;
if (this.state.offsetVideosCount !== offsetVideosCount) {
if (offsetVideosCountCeil === this.props.videos.length) {
this.scrollResponder._root.refs._rnkasv_keyboardView.scrollToEnd({animated: true});
} else {
this.scrollResponder._root.scrollToPosition(
e.nativeEvent.contentOffset.x,
offsetVideosCount * videoHeight,
true
);
}
this.setState({
offsetVideosCount,
});
}
}
whatsOnEnd() {
console.log('fire');
if(typeof this.videos !== 'undefined' || this.videos.length > 0) {
this.videos.forEach((video, videoId) => {
console.log(video, videoId);
});
}
}
renderListError() {
console.log(arguments);
}
render() {
return (
<Container style={stylesVars.container}>
<Header
hasTabs
noShadow
>
<Grid>
<Row style={{ minHeight: this.state.hashtagContainerMinHeight }}>
<TextInput
inputStyle={styles.inputStyle}
underlineColorAndroid="transparent"
/>
</Row>
</Grid>
</Header>
<Content
ref={(ref) => this.scrollResponder = ref}
onScroll={this.whatsOnScroll.bind(this)}
scrollEventThrottle={200}
>
<List
styles={styleVars.ListViewStyle}
dataArray={this.state.items}
renderRow={this.renderRow.bind(this)}
initialListSize={2}
renderError={this.renderListError}
enableEmptySections={true}
onEndReached={this.whatsOnEnd.bind(this)}
/>
</Content>
<Footer style={styles.footerStyle}>
<FooterTab>
<Button>
<Text>Home</Text>
<Icon name="ios-home"/>
</Button>
<Button>
<Text>NewClip</Text>
<Icon name="logo-youtube"/>
</Button>
<Button>
<Text>Chat</Text>
<Icon name="ios-chatbubbles"/>
</Button>
<Button>
<Text>Selection</Text>
<Icon name="ios-thumbs-up"/>
</Button>
<Button>
<Text>Setting</Text>
<Icon name="ios-cog"/>
</Button>
</FooterTab>
</Footer>
);
}
}
AppRegistry.registerComponent('App');

In both.
Well, it works with regular ListView, so its specific to List component and Content. You can test it first with ListView and do it with List to see the difference.
You don't really need Content if you're using List, so please replace it with View and check.
Changed it to this:
<List
ref={(ref) => this.scrollResponder = ref}
onScroll={this.whatsOnScroll.bind(this)}
scrollEventThrottle={200}
styles={styleVars.ListViewStyle}
dataArray={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
initialListSize={2}
renderError={this.renderListError}
enableEmptySections={true}
onEndReached={this.whatsOnEnd.bind(this)}
/>
now its working fine, but I cannot get:
this.scrollResponder._root.refs._rnkasv_keyboardView.scrollToEnd({animated: true});
and
this.scrollResponder._root.scrollToPosition(
e.nativeEvent.contentOffset.x,
offsetVideosCount * videoHeight,
true
);`
scrollToPosition on ScrollView reference can be replaced with
scrollToPosition({
x: e.nativeEvent.contentOffset.x,
y: offsetVideosCount * videoHeight,
animated: true
});`
But because in List there is no ScrollView reference, how to walkaround this issue?
You can take the listView ref as well, to scroll.
I can't did you take a look whats in console.log(ref)?
Just:
<List
ref={(ref) => console.log(ref)}
and you will see, that there is no scrollView anywhere, not in _root.refs, not in refs, not in any other properties and none of them has scrollTo or scrollToEnd.
Ideally if ListView has scrollTo function, List should too. And AFAIK, ListView is an extension of ScrollView. I'm not very sure though.
Well on List it doesn't work on ListView it does scrollTo, think its because how scrollTo is coded, it uses scrollComponent reference inside ListView and ListView is not referenced to List. So the same problem is here: https://github.com/GeekyAnts/NativeBase/issues/555
So someone just needs to do a small fix and add new release. :-)
What you saying is true, but in List component itself the reference of ListView is not returned to List component. Its only returned if dataArray and renderRow is not used, but then the Views reference is returned. Well at least its like that in latest version, checkout List here: https://github.com/GeekyAnts/NativeBase/blob/master/src/basic/List.js#L21 no ref in JSX on ListView and I think its not passed via ref as it is special property, which can go only one level in hierachy and unless you in child components attached more references to parent components. I can only hardcode that ref in.
As you can see here: https://facebook.github.io/react/docs/refs-and-the-dom.html That ref can't assign refs of child component by going ref. What I mean:
ref={(ref) => this.blabla = ref((ref2) => this.blabla2 = ref2)}
is not possible. If you want to get childrens children reference, you have to assign it to childrens children, else its null, so in other words nesting by default is not available, unless you create it.
I've added this pull request, which should fix the issue: https://github.com/GeekyAnts/NativeBase/pull/561
Using this.refs.myList._root.root.scrollTo({x: 0, x: 0, animated: true}) worked for me. Note the extra root.
@daniel-van-niekerk, yes it does, because it is ListView method, not ScrollView. ScrollToEnd or onEndReached is scrollView methods, so they do not get back references from ListView reference. That why you need reference to _scrollComponent from ListView, so you could access ScrollView methods.
Most helpful comment
You don't really need
Contentif you're usingList, so please replace it with View and check.