添加新数据时,FlatList 重新渲染所有数据 [英] FlatList re-render all data when new data is added
问题描述
我测试了 FlatList.这是我想要做的:
1.使用componentDidmount
获取10个初始数据2. 向下滚动以获取另外 10 个数据
App.js
从'react'导入React;进口 {看法,安全区视图,文本,平面列表,来自'反应原生';从 'lodash.throttle' 导入油门;从'./src/data/tmpdata'导入{tmpPosts};类 App 扩展了 React.Component {构造函数(道具){超级(道具);this.page = 0;this.state = {帖子:[],};this.getMoreDataThrottled = 油门(this.getMoreData, 3000);}componentDidMount() {console.log('comoponentDidMount')this.getMoreDataThrottled();}componentWillUnmount() {this.getMoreDataThrottled.cancel();}getMoreData = () =>{console.log('开始获取更多数据')const tmpList = []for (让 i = 0; i <10; i++ ) {tmpList.push(tmpPosts[this.page])this.page += 1;}this.setState(prevState => ({帖子:prevState.posts.concat(tmpList)}));}renderPost = ({item}) =>{控制台.log(item.id)返回 (<视图样式={{height: 200}}><Text>{item.id}</Text></查看>);};使成为() {返回 (<SafeAreaView><平面列表数据={this.state.posts}renderItem={this.renderPost}keyExtractor={post =>字符串(post.id)}initialNumToRender={10}onEndReachedThreshold={0.01}onEndReached={this.getMoreDataThrottled}/></SafeAreaView>);}}导出默认应用程序;
tmpdata.js
let num = 0;导出常量 tmpPosts = [{id: String(num += 1)},{id: String(num += 1)},...]
我实现了我想要的,但渲染发生了很多.
这是 console.log
组件DidMount开始获取更多数据123...8910123...8910开始获取更多数据123...8910123...181920开始获取更多数据123...181920123...282930
看来日志的意思是:
1. 每次重新渲染两次.
2. FlatList 渲染次数增加,因为它也会渲染旧数据.
我检查了类似的问题,它似乎是 FlatList 的常规行为.
原答案
我想你忘了在你的平面列表中添加道具extraData":
字符串(post.id)}initialNumToRender={10}onEndReachedThreshold={0.01}onEndReached={this.getMoreDataThrottled}/>
https://facebook.github.io/react-native/docs/flatlist#extradata
PS : 可能会扩展 PureComponent
PS2:你需要你的渲染项目(renderPost)有一个带有唯一键的道具id"
renderPost = ({item}) =>{控制台.log(item.id)返回 (<视图id={item.id} style={{height: 200}}><Text>{item.id}</Text></查看>);};
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?
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>
);
};
这篇关于添加新数据时,FlatList 重新渲染所有数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!