我正在尝试在 React Native 中实现无限滚动.以下是组件的来源:
I am trying to implement an infinite scroll in React Native. Below is the source of the component:
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 方法不会触发.它只是重新渲染每一行,即使没有任何变化(新数据除外).知道为什么绕过该方法吗?
The problem is that whenever I append (or prepend) new data, the rowHasChanged method of the DataSource doesn't fire. It just re-renders every row, even tho nothing has changed (except the new data). Any idea why the method is bypassed?
推荐答案将函数传递给 setState 以避免竞争条件
Pass a function to setState to avoid race conditions
我刚刚想通了.如果您遇到同样的问题,请检查您使用新的 dataSource 更改状态的点.我的是这样的:
I just figured it out. If you are having the same issue, check the point at which you change your state with the new dataSource. Mine was like this:
this.setState({ dataSource: this.ds.cloneWithRows(posts) });相反,您应该始终使用先前状态中的 dataSource,如下所示:
Instead you should always use the dataSource from the previous state, like this:
this.setState(state => ({ dataSource: state.dataSource.cloneWithRows(posts) }))干杯!
更多推荐
React Native ListView
发布评论