I put together a simple React-native application to gets data from a remote service, loads it in a FlatList. When a user taps on an item, it should be highlighted and selection should be retained. I am sure such a trivial operation should not be difficult. I am not sure what I am missing.
import React, { Component } from 'react'; import { StyleSheet, Text, View, FlatList, ActivityIndicator, Image, TouchableOpacity, } from 'react-native'; export default class BasicFlatList extends Component { constructor(props) { super(props); this.state = { loading: false, data: [], page: 1, seed: 1, error: null, refreshing: false, selectedItem:'null', }; } componentDidMount() { this.makeRemoteRequest(); } makeRemoteRequest = () => { const {page, seed} = this.state; const url = `https://randomuser.me/api/?seed=${seed}&page=${page}&results=20`; this.setState({loading: true}); fetch(url) .then(res => res.json()) .then(res => { this.setState({ data: page === 1 ? res.results : [...this.state.data, ...res.results], error: res.error || null, loading: false, refreshing: false }); }) .catch(error => { this.setState({error, loading: false}); }); }; onPressAction = (rowItem) => { console.log('ListItem was selected'); console.dir(rowItem); this.setState({ selectedItem: rowItem.id.value }); } renderRow = (item) => { const isSelectedUser = this.state.selectedItem === item.id.value; console.log(`Rendered item - ${item.id.value} for ${isSelectedUser}`); const viewStyle = isSelectedUser ? styles.selectedButton : styles.normalButton; return( <TouchableOpacity style={viewStyle} onPress={() => this.onPressAction(item)} underlayColor='#dddddd'> <View style={styles.listItemContainer}> <View> <Image source={{ uri: item.picture.large}} style={styles.photo} /> </View> <View style={{flexDirection: 'column'}}> <View style={{flexDirection: 'row', alignItems: 'flex-start',}}> {isSelectedUser ? <Text style={styles.selectedText}>{item.name.first} {item.name.last}</Text> : <Text style={styles.text}>{item.name.first} {item.name.last}</Text> } </View> <View style={{flexDirection: 'row', alignItems: 'flex-start',}}> <Text style={styles.text}>{item.email}</Text> </View> </View> </View> </TouchableOpacity> ); } render() { return( <FlatList style={styles.container} data={this.state.data} renderItem={({ item }) => ( this.renderRow(item) )} /> ); } } const styles = StyleSheet.create({ container: { flex: 1, marginTop: 50, }, selectedButton: { backgroundColor: 'lightgray', }, normalButton: { backgroundColor: 'white', }, listItemContainer: { flex: 1, padding: 12, flexDirection: 'row', alignItems: 'flex-start', }, text: { marginLeft: 12, fontSize: 16, }, selectedText: { marginLeft: 12, fontSize: 20, }, photo: { height: 40, width: 40, borderRadius: 20, }, });
When user taps on an item in the list, "onPress" method is invoked with the information on selected item. But the next step of highlight item in Flatlist does not happen. 'UnderlayColor' is of no help either.
Any help/advice will be much appreciated.
To get the index of the currently visible item in a React Native flat list, we can set the onViewableItemsChange prop to a function that gets the current visible items. to define the onViewableItemsChanged function that gets the viewableItems property.
keyExtractor (item: object, index: number) => string; Used to extract a unique key for a given item at the specified index. Key is used for caching and as the react key to track item re-ordering. The default extractor checks item. key , then item.id , and then falls back to using the index, like React does.
You can do something like:
For the renderItem, use something like a TouchableOpacity with an onPress event passing the index or id of the renderedItem;
Function to add the selected item to a state:
handleSelection = (id) => { var selectedId = this.state.selectedId if(selectedId === id) this.setState({selectedItem: null}) else this.setState({selectedItem: id}) } handleSelectionMultiple = (id) => { var selectedIds = [...this.state.selectedIds] // clone state if(selectedIds.includes(id)) selectedIds = selectedIds.filter(_id => _id !== id) else selectedIds.push(id) this.setState({selectedIds}) }
FlatList:
<FlatList data={data} extraData={ this.state.selectedId // for single item this.state.selectedIds // for multiple items } renderItem={(item) => <TouchableOpacity // for single item onPress={() => this.handleSelection(item.id)} style={item.id === this.state.selectedId ? styles.selected : null} // for multiple items onPress={() => this.handleSelectionMultiple(item.id)} style={this.state.selectedIds.includes(item.id) ? styles.selected : null} > <Text>{item.name}</Text> </TouchableOpacity> }
/>
Make a style for the selected item and that's it!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With