当添加新数据时,React Native FlatList重新渲染已经渲染的项目 [英] React Native FlatList re-renders the already rendered items when adding new data

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

问题描述

我已经实现了一个侦听我的数据库文档的代码,当添加一个新文档时,应用程序会将其作为我FlatList中的一个项目呈现.

I have implemented a code that listen my DB documents and when a new one is added the app renders it as an item on my FlatList.

我遇到的问题是,每当我更新FlatList的数据时,已经渲染的项目就会一次又一次地重新呈现...

The problem I have is that everytime I update the data of the FlatList, the already rendered items re-renders again and again...

由于我的原始代码很复杂,因此我构建了一个Snack: https://snack.expo.io/@victoriomolina/flatlist-重新渲染所有组件

As my original code is complex, I have build a Snack: https://snack.expo.io/@victoriomolina/flatlist-re-renders-all-components

我认为问题在于我使用现有数组的浅表副本来更新状态,但这样做只是为了在添加新项目时重新呈现FlatList.渲染已渲染的项目).

I think the problem is that I update the state using a shallow copy of the existing array, but I do it just to re-render the FlatList when new items are added (I don't want to re-render the already rendered items).

谢谢,非常感谢您的帮助.

Thank you, I will really appreciate your help.

Pd:在我的原始代码中,FlatList的组件扩展了React.PureComponent

Pd: In my original code the components of the FlatList extends React.PureComponent

穿行部分

  const [posts, setPosts] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const { firebase } = props;

    let postsArray = [];

    // Realtime database listener
    const unsuscribe = firebase
      .getDatabase()
      .collection("posts")
      .doc(firebase.getCurrentUser().uid)
      .collection("userPosts")
      .orderBy("date") // Sorted by upload date
      .onSnapshot((snapshot) => {
        let changes = snapshot.docChanges();

        changes.forEach((change) => {
          if (change.type === "added") {
            // Get the new post
            const newPost = change.doc.data();

            // Add the new post to the posts list
            postsArray.unshift(newPost);
          }
        });

        // Reversed order so that the last post is at the top of the list
        setPosts([...postsArray]); // Shallow copy of the existing array -> Re-render when new posts added
        setIsLoading(false);
      });

    /* Pd: At the first time, this function will get all the user's posts */

    return () => {
      // Detach the listening agent
      unsuscribe();
    };
  }, []);

FlatList

     <FlatList
          data={data}
          keyExtractor={keyExtractor}
          legacyImplementation={false}
          numColumns={1}
          renderItem={this.renderItem}
          getItemLayout={this.getItemLayout}
          initialNumToRender={12}
          windowSize={40}
          maxToRenderPerBatch={15}
          updateCellsBatchingPeriod={50}
          removeClippedSubviews
          ListFooterComponent={this.renderFooter()}
        />

渲染项方法

renderItem = ({ item, index }) => {
    const {
      images,
      dimensions,
      description,
      location,
      likes,
      comments,
      date,
    } = item;

    return (
      <View
        key={index}
        onLayout={({ nativeEvent }) => {
          this.itemHeights[index] = nativeEvent.layout.height;
        }}
      >
        <Card { /* Extends React.PureComponent */ }
          images={images}
          postDimensions={dimensions}
          description={description}
          location={location}
          likes={likes}
          comments={comments}
          date={date}
        />
      </View>
    );
  };

推荐答案

对我有用的解决方案:

  1. 在渲染项中,我将索引作为项的键传递.我已经读到这会产生奇怪的行为,所以我决定改为传递item.id(这是一个UUID).

  1. In render item I was passing the index as a key to the item. I have read that this can produce strange behaviour, so I decided to pass item.id (which is an UUID) instead.

将PureComponent更改为标准组件,然后重新实现componentShouldUpdate生命周期方法.如果您有PureComponent,它将是:

Change the PureComponent to a Standard Component and reimplement the componentShouldUpdate life-cycle method. If you have a PureComponent it will be:

 // From the RN documentation
 shouldComponentUpdate(nextProps, nextState) {
     return nextProps !== this.props && nextState !== this.state;
 }

因此,我决定将Item更改为普通的Component并执行以下操作:

So, I have decided to change my Item to a normal Component and do:

shouldComponentUpdate(nextProps, nextState) {
   // My component is just a card with an author row and a progressive image (thumbnail + image) with a Skeleton absolutely positioned
   return nextState.avatarIsLoaded && nextState.thumbailIsLoaded; // && nextState.imageIsLoaded is unnecesary by the way I have implemented my component
}

Pd:最好也像我一样做,因为如果我加上*&&nextState.imageIsLoaded *我将需要等待很长时间才能加载完整的图像(其大小大于缩略图的大小).

Pd: Also it is better to do as I did because if I add the * && nextState.imageIsLoaded * I will have to wait a long time until the full image (which size is bigger than the thumbnail's one) is loaded.

现在我的项目渲染两次,首先是在显示骨骼"时,然后是在准备显示渐进式图像时.

Now my items render twice, firstly when the Skeleton is showed, and secondly when the progressive image is ready to being displayed.

这篇关于当添加新数据时,React Native FlatList重新渲染已经渲染的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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