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.
The problem I have is that everytime I update the data of the FlatList, the already rendered items re-renders again and again...
As my original code is complex, I have build a Snack: https://snack.expo.io/@victoriomolina/flatlist-re-renders-all-components
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: In my original code the components of the FlatList extends React.PureComponent
My Real Code
The fething part
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();
};
}, []);
The 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()}
/>
The render item method
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>
);
};