我试图在React Native中实现无限滚动.以下是组件的来源:
- var React = require('react-native');
- var server = require('../server');
- var Post = require('./Post');
- var SwipeRefreshLayoutAndroid = require('./SwipeRefreshLayout');
- var backEvent = null;
- var lastPostId = "";
- var isLoadingMore = false;
- var isLoadingTop = false;
- var onEndReachedActive = false;
- var {
- StyleSheet,ListView,View,Text,Image,ProgressBarAndroid,BackAndroid
- } = React;
- class Stream extends React.Component {
- constructor(props) {
- super(props);
- this.ds = new ListView.DataSource({
- rowHasChanged: (row1,row2) => {
- console.log("rowHasChenged FIRED!!");
- return false;
- }
- });
- this.state = {
- dataSource: this.ds.cloneWithRows(['loader']),hasStream: false,posts: []
- };
- }
- componentDidMount() {
- BackAndroid.addEventListener('hardwareBackPress',() => {
- this.props.navigator.jumpBack();
- return true;
- }.bind(this));
- server.getStream('','',15).then((res) => {
- lastPostId = res[res.length-1].m._id;
- this.setState({
- posts: res,hasStream: true,dataSource: this.ds.cloneWithRows(res)
- },() => onEndReachedActive = true);
- })
- }
- onRefresh() {
- var posts = this.state.posts;
- var firstPost = posts[0].m._id;
- console.log(this.state.dataSource._rowHasChanged);
- isLoadingTop = true;
- server.getStream('',firstPost,4000)
- .then(res => {
- console.log(posts.length);
- posts = res.concat(posts);
- console.log(posts.length);
- this.setState({
- dataSource: this.ds.cloneWithRows(posts),posts
- },() => {
- this.swipeRefreshLayout && this.swipeRefreshLayout.finishRefresh();
- isLoadingTop = false;
- });
- }).catch((err) => {
- isLoadingTop = false;
- })
- }
- onEndReached(event) {
- if(!onEndReachedActive) return;
- if(this.state.loadingMore || this.state.isLoadingTop)return;
- isLoadingMore = true;
- var posts = this.state.posts;
- server.getStream(posts[posts.length-1].m._id,15)
- .then(res => {
- console.log('received posts');
- posts = posts.concat(res);
- lastPostId = posts[posts.length-1].m._id;
- this.setState({
- dataSource: this.ds.cloneWithRows(posts),posts
- },()=>isLoadingMore = false);
- })
- }
- renderHeader() {
- return (
- <View style={styles.header}>
- <Text style={styles.headerText}>Header</Text>
- </View>
- )
- }
- renderRow(post) {
- if(post === 'loader') {
- return (
- <ProgressBarAndroid
- styleAttr="Large"
- style={styles.spinnerBottom}/>
- )
- }
- let hasLoader = post.m._id === lastPostId;
- let loader = hasLoader ?
- <ProgressBarAndroid
- styleAttr="Large"
- style={styles.spinnerBottom}/> : null;
- return (
- <View>
- <Post
- post={post}/>
- {loader}
- </View>
- )
- }
- render() {
- return (
- <ListView
- style={styles.mainContainer}
- dataSource={this.state.dataSource}
- renderRow={this.renderRow.bind(this)}
- onEndReached={this.onEndReached.bind(this)}
- onEndReachedThreshold={1}
- pageSize={15} />
- );
- }
- }
问题是每当我追加(或前置)新数据时,DataSource的rowHasChanged方法都不会触发.它只是重新渲染每一行,即使没有任何变化(新数据除外).
知道为什么绕过这个方法吗?
编辑:将函数传递给setState以避免竞争条件
我刚想通了.如果遇到相同的问题,请检查使用新dataSource更改状态的位置.我是这样的:
- this.setState({
- dataSource: this.ds.cloneWithRows(posts)
- });
相反,您应该始终使用之前状态的dataSource,如下所示:
- this.setState(state => ({
- dataSource: state.dataSource.cloneWithRows(posts)
- }))
干杯!