FlatList 在添加新数据时重新渲染所有数据
FlatList re-render all data when new data is added
我测试 FlatList。这是我想要做的:
1.用componentDidmount
得到10个初始数据
2. 向下滚动以获取更多 10 个数据
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)},
.
.
.
]
我实现了我想要的,但是渲染出现很多。
这里是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
日志的意思似乎是:
1. 每次重新渲染两次。
2. FlatList渲染num增加,因为它也渲染旧数据
我检查了类似的问题,这似乎是 FlatList 的正常行为。
FlatList renderItem is called multiple times
https://github.com/facebook/react-native/issues/14528
但是我担心当数据超过100时应用程序会变慢并崩溃。
FlatList 性能的最佳解决方案是什么?
shouldComponentUpdate 防止不必要的重新渲染,例如已经渲染过的旧数据?
更新
抱歉,我的回复不完整。我重现了您的问题并通过将您的 "Post" 组件移动到一个单独的文件中来修复它。
post 扩展了 pureComponent,所以如果它的 props 没有改变,它就不会重新渲染。
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;
原回答
我想你忘了在你的平面列表中添加道具 "extraData" :
<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 :可能会扩展 PureComponent
PS2:你需要你的渲染项目(renderPost)有一个道具"id"和一个唯一的键
renderPost = ({item}) => {
console.log(item.id)
return (
<View id={item.id} style={{height: 200}}>
<Text>{item.id}</Text>
</View>
);
};
卸载并转为原生。 RN 漏洞百出
https://softwareengineeringdaily.com/2018/09/24/show-summary-react-native-at-airbnb/
我测试 FlatList。这是我想要做的:
1.用componentDidmount
得到10个初始数据
2. 向下滚动以获取更多 10 个数据
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)},
.
.
.
]
我实现了我想要的,但是渲染出现很多。
这里是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
日志的意思似乎是:
1. 每次重新渲染两次。
2. FlatList渲染num增加,因为它也渲染旧数据
我检查了类似的问题,这似乎是 FlatList 的正常行为。
FlatList renderItem is called multiple times
https://github.com/facebook/react-native/issues/14528
但是我担心当数据超过100时应用程序会变慢并崩溃。
FlatList 性能的最佳解决方案是什么?
shouldComponentUpdate 防止不必要的重新渲染,例如已经渲染过的旧数据?
更新
抱歉,我的回复不完整。我重现了您的问题并通过将您的 "Post" 组件移动到一个单独的文件中来修复它。 post 扩展了 pureComponent,所以如果它的 props 没有改变,它就不会重新渲染。
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;
原回答
我想你忘了在你的平面列表中添加道具 "extraData" :
<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 :可能会扩展 PureComponent
PS2:你需要你的渲染项目(renderPost)有一个道具"id"和一个唯一的键
renderPost = ({item}) => {
console.log(item.id)
return (
<View id={item.id} style={{height: 200}}>
<Text>{item.id}</Text>
</View>
);
};
卸载并转为原生。 RN 漏洞百出
https://softwareengineeringdaily.com/2018/09/24/show-summary-react-native-at-airbnb/