添加新数据时,FlatList 重新渲染所有数据 [英] FlatList re-render all data when new data is added

查看:137
本文介绍了添加新数据时,FlatList 重新渲染所有数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我测试了 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆