添加新数据后,FlatList重新呈现所有数据

时间:2019-08-06 17:35:58

标签: react-native react-native-flatlist

我测试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渲染数增加,因为它也渲染旧数据。

我检查了类似的问题,这似乎是FlatList的正常行为。
FlatList renderItem is called multiple times
FlatList calling twice
https://github.com/facebook/react-native/issues/14528

但是,恐怕当数据达到100多个时,该应用程序将运行缓慢并崩溃。
FlatList性能的最佳解决方案是什么?
ComponentUpdate是否应防止不必要的重新渲染,例如已经渲染的旧数据?

2 个答案:

答案 0 :(得分:0)

更新

对不起,我的回答不完整。我转载了您的问题,并通过将“ 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;

enter image description here

原始答案

我认为您忘了在道具列表中添加道具“ 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>
    );
  };

答案 1 :(得分:-9)