问题
I test FlatList. Here is what I want to do:
1. Get 10 initial data with componentDidmount
2. Scroll down to get 10 more data
App.js
import React from 'react';
import {
View,
SafeAreaView,
Text,
FlatList,
} from 'react-native';
import throttle from 'lodash.throttle';
import { tmpPosts } from './src/data/tmpdata';
class App extends React.Component {
constructor(props) {
super(props);
this.page = 0;
this.state = {
posts: [],
};
this.getMoreDataThrottled = throttle(this.getMoreData, 3000);
}
componentDidMount() {
console.log('comoponentDidMount')
this.getMoreDataThrottled();
}
componentWillUnmount() {
this.getMoreDataThrottled.cancel();
}
getMoreData = () => {
console.log('start getMoreData')
const tmpList = []
for (let i = 0; i < 10; i++ ) {
tmpList.push(tmpPosts[this.page])
this.page += 1;
}
this.setState(prevState => ({
posts: prevState.posts.concat(tmpList)
}));
}
renderPost = ({item}) => {
console.log(item.id)
return (
<View style={{height: 200}}>
<Text>{item.id}</Text>
</View>
);
};
render() {
return (
<SafeAreaView>
<FlatList
data={this.state.posts}
renderItem={this.renderPost}
keyExtractor={post => String(post.id)}
initialNumToRender={10}
onEndReachedThreshold={0.01}
onEndReached={this.getMoreDataThrottled}
/>
</SafeAreaView>
);
}
}
export default App;
tmpdata.js
let num = 0;
export const tmpPosts = [
{id: String(num += 1)},
{id: String(num += 1)},
.
.
.
]
I implemented what I want, but the rendering occurs much.
Here is console.log
comoponentDidMount
start getMoreData
1
2
3
.
.
.
8
9
10
1
2
3
.
.
.
8
9
10
start getMoreData
1
2
3
.
.
.
8
9
10
1
2
3
.
.
.
18
19
20
start getMoreData
1
2
3
.
.
.
18
19
20
1
2
3
.
.
.
28
29
30
It seems the log means:
1. Re-rendering occurs twice every time.
2. FlatList rendering num increases, because it renders old data too.
I check similar issue, and it seems regular behaviour of FlatList.
FlatList renderItem is called multiple times
FlatList calling twice
https://github.com/facebook/react-native/issues/14528
However I'm afraid that the app will be slow and crashed when the data reaches 100 more.
What is the best solution for FlatList performance?
shouldComponentUpdate prevent unnecessary re-rendering such as old data that has already been rendered?
回答1:
Update
Sorry, my response was incomplete. I reproduced your problem and fixed it by moving your "Post" component in a separate file. This post extend pureComponent, so it'll not re render if it's props doesn't changed.
class App extends React.Component {
constructor(props) {
super(props);
this.page = 0;
this.state = {
posts: []
};
this.getMoreDataThrottled = throttle(this.getMoreData, 3000);
}
componentDidMount() {
console.log("comoponentDidMount");
this.getMoreData();
}
componentWillUnmount() {
this.getMoreDataThrottled.cancel();
}
getMoreData = () => {
console.log("start getMoreData");
const tmpList = [];
for (let i = 0; i < 10; i++) {
tmpList.push(tmpPosts[this.page]);
this.page += 1;
}
this.setState(prevState => ({
posts: prevState.posts.concat(tmpList)
}));
};
renderPost = ({ item }) => {
return <Post item={item} />;
};
render() {
return (
<SafeAreaView>
<FlatList
data={this.state.posts}
renderItem={this.renderPost}
keyExtractor={post => String(post.id)}
initialNumToRender={10}
onEndReachedThreshold={0.5}
onEndReached={this.getMoreData}
/>
</SafeAreaView>
);
}
}
/*
In a separate file
*/
class Post extends React.PureComponent {
render() {
const { item } = this.props;
console.log(item.id);
return (
<View key={item.id} style={{ height: 200 }}>
<Text>{item.id}</Text>
</View>
);
}
}
// Same but in functional (my preference)
const _PostItem =({ item }) => {
console.log(item.id);
return (
<View key={item.id} style={{ height: 200 }}>
<Text>{item.id}</Text>
</View>
);
};
export const PostFunctionalWay = React.memo(_PostItem);
export default App;
Original answer
I think you forgot to add the prop "extraData" in your flatlist :
<FlatList
data={this.state.posts}
extraData={this.state.posts}
renderItem={this.renderPost}
keyExtractor={post => String(post.id)}
initialNumToRender={10}
onEndReachedThreshold={0.01}
onEndReached={this.getMoreDataThrottled}
/>
https://facebook.github.io/react-native/docs/flatlist#extradata
PS : maybe with extending PureComponent
PS2 : you need that your rendering items(renderPost) have a prop "id" with a unique key
renderPost = ({item}) => {
console.log(item.id)
return (
<View id={item.id} style={{height: 200}}>
<Text>{item.id}</Text>
</View>
);
};
回答2:
Uninstall and go native. RN is full of bugs.
https://softwareengineeringdaily.com/2018/09/24/show-summary-react-native-at-airbnb/
来源:https://stackoverflow.com/questions/57381341/flatlist-re-render-all-data-when-new-data-is-added