I am trying to figure out this for days, but my component ImageComponent is flickering when I click add or remove for all the elements in the array. I think the issue is that all elements in the array is re-rendering when one element is updated. How can I fix this? I have been trying using memo and useMemo, as well as useCallback, but none worked… could anyone figure this out, please?
Main
const [addAlcoholList, setAddAlcoholList] = useState([
{ name: 'soju', icon: 'soju', count: 0 },
{ name: 'beer', icon: 'beer', count: 0 }
]);
const changeUnitCount = useCallback((index, change) => {
// console.log('changeUnitCount rendered for', addAlcoholList[index].name);
setAddAlcoholList((prev) => {
const newCount = prev[index].count + change;
if (newCount < 0) {
Alert.alert(`Delete ${prev[index].name}`, 'Are you sure you want to delete this?', [
{
text: 'Cancel',
style: 'cancel'
},
{
text: 'Delete',
onPress: () => {
setAddAlcoholList(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]);
},
style: 'destructive'
},
]);
} else {
const updatedList = [...prev];
updatedList[index] = { ...updatedList[index], count: newCount };
return updatedList;
}
return prev;
});
}, []);
const AlcoholUnit = React.memo(({ alcohol, index, changeUnitCount }) => {
useEffect(() => {
console.log(`${alcohol.name} component rerendered: ${alcohol.count}`);
});
return (
<View style={styles.addUnitContainer}>
<TouchableOpacity onPress={() => changeUnitCount(index, -1)}>
<Icon name="remove" color={"#c1dfb0"} size={50} />
</TouchableOpacity>
<View style={styles.addUnit}>
<ImageComponent type={'alcohol'} value={alcohol.icon} size={30} />
<Text style={styles.text}>{alcohol.name}</Text>
</View>
<Text style={styles.text}>{alcohol.count}</Text>
<TouchableOpacity onPress={() => changeUnitCount(index, 1)}>
<Icon name="add" color={"#c1dfb0"} size={50} />
</TouchableOpacity>
</View>
);
});
return (
...
{addAlcoholList.map((item, i) => (
<AlcoholUnit key={`${item.name}`} index={i} alcohol={item} changeUnitCount={changeUnitCount} />
))}
);
ImageComponent.jsx
const ImageComponent = memo(({ type, value, size = 30 }) => {
const source = getImage(type, value);
if (!source) {
return null; // Return null if the source is invalid
}
console.log(`Image rendered: ${type} ${value}`);
return (
<Image
style={{ width: size, height: size }}
source={source}
contentFit="contain"
/>
);
}, (prevProps, nextProps) => prevProps.value === nextProps.value && prevProps.size === nextProps.size);
export default ImageComponent;
I have been trying using memo, useMemo, and useCallback to avoid re-rendering of components but did not work. I might have been implementing it incorrectly.
seans is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.