Created
July 16, 2025 15:09
-
-
Save williamjayjay/a183c555115e90eea967cb4edd61c39f to your computer and use it in GitHub Desktop.
performance, react memo multiselect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { memo, useCallback, useState } from 'react'; | |
import { FlatList, Text, Button, View, StyleSheet, Pressable } from 'react-native'; | |
// Interface para os dados de cada item da lista | |
interface ItemData { | |
id: string; | |
selected: boolean; // Indica se o item está selecionado | |
} | |
// Interface para as propriedades do componente Item | |
interface ItemProps { | |
id: string; | |
selected: boolean; // Propriedade para indicar se o item está selecionado | |
onPress: (id: string) => void; // Função para lidar com o toque curto | |
onLongPress: (id: string) => void; // Função para lidar com o toque longo | |
} | |
// Componente Item memoizado para otimização de performance | |
const Item: React.FC<ItemProps> = memo(({ id, selected, onPress, onLongPress }) => { | |
console.count(`Renderizações do Item ${id}`); | |
return ( | |
<Pressable | |
onPress={() => onPress(id)} // Chama a função de toque curto | |
onLongPress={() => onLongPress(id)} // Chama a função de toque longo | |
style={({ pressed }) => [ | |
styles.item, | |
selected && styles.selectedItem, // Aplica estilo se o item estiver selecionado | |
pressed && styles.pressedItem, // Feedback visual ao pressionar | |
]} | |
> | |
<Text style={styles.itemText}>Item {id}</Text> | |
{selected && <Text style={styles.selectedIndicator}>✓</Text>} | |
</Pressable> | |
); | |
}); | |
// Componente principal do aplicativo | |
const App: React.FC = () => { | |
// Estado para o contador, para testar re-renderizações da lista | |
const [count, setCount] = useState<number>(0); | |
// Estado para os itens da lista, incluindo seu estado de seleção | |
const [items, setItems] = useState<ItemData[]>( | |
Array.from({ length: 100 }, (_, i) => ({ id: i.toString(), selected: false })) | |
); | |
// Estado para controlar se o modo de seleção múltipla está ativo | |
const [selectionMode, setSelectionMode] = useState<boolean>(false); | |
// Calcula o número de itens selecionados dinamicamente | |
const selectedCount = items.filter(item => item.selected).length; | |
// Função useCallback para lidar com o toque curto em um item | |
const handleItemPress = useCallback((id: string) => { | |
if (selectionMode) { | |
// Alterna o estado 'selected' do item | |
setItems(prevItems => | |
prevItems.map(item => | |
item.id === id ? { ...item, selected: !item.selected } : item | |
) | |
); | |
} else { | |
console.log(`Item ${id} clicado normalmente`); | |
} | |
}, [selectionMode]); | |
// Função useCallback para lidar com o toque longo em um item | |
const handleItemLongPress = useCallback((id: string) => { | |
setSelectionMode(true); | |
setItems(prevItems => | |
prevItems.map(item => | |
item.id === id ? { ...item, selected: true } : item | |
) | |
); | |
}, []); | |
// Função useCallback para limpar apenas os itens selecionados | |
const clearSelection = useCallback(() => { | |
setSelectionMode(false); | |
// Atualiza apenas os itens que estão selecionados | |
setItems(prevItems => | |
prevItems.map(item => | |
item.selected ? { ...item, selected: false } : item | |
) | |
); | |
}, []); | |
// Função useCallback para renderizar cada item na FlatList | |
const renderItem = useCallback( | |
({ item }: { item: ItemData }) => ( | |
<Item | |
id={item.id} | |
selected={item.selected} | |
onPress={handleItemPress} | |
onLongPress={handleItemLongPress} | |
/> | |
), | |
[handleItemPress, handleItemLongPress] | |
); | |
return ( | |
<View style={styles.container}> | |
<View style={styles.controls}> | |
<Button | |
title="Incrementar Contador" | |
onPress={() => setCount(count + 1)} | |
color="#2196F3" | |
/> | |
<Text style={styles.counter}>Contador: {count}</Text> | |
{selectionMode && ( | |
<Button | |
title={`Limpar Seleção (${selectedCount})`} | |
onPress={clearSelection} | |
color="red" | |
/> | |
)} | |
</View> | |
<FlatList | |
data={items} | |
renderItem={renderItem} | |
keyExtractor={(item: ItemData) => item.id} | |
extraData={selectionMode} | |
/> | |
</View> | |
); | |
}; | |
// Estilos para os componentes | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
paddingTop: 50, | |
backgroundColor: '#f0f0f0', | |
}, | |
controls: { | |
padding: 15, | |
borderBottomWidth: 1, | |
borderBottomColor: '#ddd', | |
backgroundColor: '#fff', | |
alignItems: 'center', | |
marginBottom: 10, | |
shadowColor: '#000', | |
shadowOffset: { width: 0, height: 2 }, | |
shadowOpacity: 0.1, | |
shadowRadius: 2, | |
elevation: 3, | |
}, | |
item: { | |
padding: 18, | |
borderBottomWidth: 1, | |
borderBottomColor: '#eee', | |
backgroundColor: '#fff', | |
flexDirection: 'row', | |
justifyContent: 'space-between', | |
alignItems: 'center', | |
marginHorizontal: 10, | |
marginVertical: 4, | |
borderRadius: 8, | |
shadowColor: '#000', | |
shadowOffset: { width: 0, height: 1 }, | |
shadowOpacity: 0.05, | |
shadowRadius: 1, | |
elevation: 1, | |
}, | |
selectedItem: { | |
backgroundColor: '#e0f7fa', | |
borderColor: '#00bcd4', | |
borderWidth: 2, | |
}, | |
pressedItem: { | |
opacity: 0.7, | |
}, | |
itemText: { | |
fontSize: 17, | |
color: '#333', | |
fontWeight: '500', | |
}, | |
selectedIndicator: { | |
fontSize: 22, | |
color: '#00bcd4', | |
fontWeight: 'bold', | |
}, | |
counter: { | |
fontSize: 22, | |
marginVertical: 15, | |
fontWeight: 'bold', | |
color: '#555', | |
}, | |
}); | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment