Search code examples
reactjsreact-nativereduxreact-redux

Prevent FlatList from re-rendering entire list when state changes


I have an array of posts in a redux reducer that I update via the onEndReached prop of my FlatList. The issue is, every time the state changes, the entire list is re-rendered rather than the affected post item.

// Posts Feed Screen

const posts = useSelector(state => state.posts)

const renderItem = useCallback(
    ({ item }) => (
        <Post post={item} />
    ),
    []
)
const keyExtractor = useCallback(
    (item, index) => `${item.id}${index}`,
    []
)

return (
    <FlatList
        ref={ref}
        data={posts}
        keyExtractor={keyExtractor}
        renderItem={renderItem}
        onEndReached={onEndReached}
        onEndReachedThreshold={0.6}
        showsVerticalScrollIndicator={false}
        removeClippedSubviews
    />
)



// Post Component

const Post = ({ post }) => {
    return (
        <View style={styles.post}>
            <PostHeader />
            <View style={styles.postBody}>
                <PostContent />
                <PostFooter />
            </View>
        </View>
    )
}

const isEqual = (prevProps, nextProps) => {
    return prevProps.post.id === nextProps.post.id
}

export default React.memo(Post, isEqual)

As you can see, I'm utilizing useCallback on renderItem function, also using React.memo on the export of my Post Component - however, the FlatList still renders every post item on state change.

What am I missing here?


Solution

  • I am going to post my comments as an answer because ultimately that is how the problem was solved:

    This is actually simpler than it seems. What happens is that when you pass "reference types" as props everytime a new reference is created the component will re-render.

    So in your reducer that updates the "posts" you should make sure you are not creating a new list every time but rather updating only properties of a single post within the list.

    Avoid spread operator for example. Also the post component should not take a post as a prop but actually an Id of the post and find it itself using the useSelector which in turn should return values of the properties.

    So for example it is better to have a useSelector per property being displayed than a single useSelector for the whole post. The reason is that the react rendering engine compares using "==" to find differences and decide how to render.

    And two objects can be exactly the same compared property by property, but yet return as different because they are different instances.

    The key here is to only update the properties that need updating inside the reducers and at the same time make sure you return value types in your useSelectors.