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/