我试图在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) }))
干杯!