I’m new to React-Native and trying to investigate why all items in my FlatList are re-rendering when I select one of them.
This is the code of the list:
import React, { useEffect, useState } from 'react';
import { FlatList, StyleSheet } from 'react-native';
import Task from './Task';
import useTasks from '../hooks/useTasks';
import TaskListHeader from './TaskListHeader';
export default function Tasks({ header: Header }) {
const [title, image, list] = useTasks()
const [doneTasksCount, setDoneTasksCount] = useState(0)
const updateCounter = (isDone) => {
isDone ? setDoneTasksCount(doneTasksCount + 1) : setDoneTasksCount(doneTasksCount - 1)
}
useEffect(() => {
const count = list.reduce((acc, cur) => cur.isDone ? ++acc : acc, 0)
setDoneTasksCount(count)
}, [list])
const renderItem = ({ item }) => {
return <Task {...item} updateCounter={updateCounter} />;
};
const header = () => {
return (
<>
<Header />
<TaskListHeader
title={title}
imageURL={image}
allTasksCount={list.length}
doneTasksCount={doneTasksCount}
/>
</>
)
}
return <>
<FlatList
data={list}
renderItem={renderItem}
keyExtractor={({ task }) => task}
ListHeaderComponent={header}
style={styles.list}
/>
</>
}
const styles = StyleSheet.create({
list: {
backgroundColor: '#EBFFEE'
}
})
And the code of the list item is this:
import React, { useState } from "react";
import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native";
export default function Task({task, icon, isDone, updateCounter}) {
const [isMarked, setIsMarked] = useState(isDone)
const handlePress = () => {
setIsMarked(!isMarked)
updateCounter(!isMarked)
};
return <View style={[styles.content, isMarked ? styles.markedContent : styles.unmarkedContent]}>
{console.log(`render ${task}`)}
<View style={styles.info}>
<Image source={icon} style={styles.icon} />
<Text style={[styles.title, isMarked ? styles.markedTitle : null]}>{task}</Text>
</View>
<TouchableOpacity
style={[styles.actionButton, isMarked ? styles.markedButton : styles.unmarkedButton]}
onPress={handlePress}
>
<Text style={styles.buttonTitle}>{isMarked ? "Feito" : "Fazer"}</Text>
</TouchableOpacity>
</View>
}
const styles = StyleSheet.create({
content: {
flexDirection: 'row',
marginBottom: 14,
borderRadius: 16,
justifyContent: 'space-between',
alignItems: 'center',
maxHeight: 100,
overflow: 'hidden',
marginHorizontal: 16
},
icon: {
width: 22,
height: 22
},
info: {
paddingLeft: 14,
paddingVertical: 32,
flexDirection: 'row',
alignItems: 'center',
},
title: {
marginLeft: 14,
fontWeight: 'bold'
},
actionButton: {
height: '100%',
justifyContent: 'center'
},
buttonTitle: {
fontWeight: 'bold',
marginHorizontal: 14
},
markedButton: {
backgroundColor: '#00EA17'
},
unmarkedButton: {
backgroundColor: '#FF5D5D'
},
markedTitle: {
textDecorationLine: 'line-through'
},
markedContent: {
backgroundColor: '#E1EFF2'
},
unmarkedContent: {
backgroundColor: '#BDBCFF'
}
})
The list has a header where I display the number of selected items.
I tried to use React.memo at the Task component but it didn’t work.