2017-10-11 5 views
2

J'ai mis en place une simple application React-native pour obtenir des données d'un service distant, le charge dans une FlatList. Lorsqu'un utilisateur appuie sur un élément, il doit être mis en surbrillance et la sélection doit être conservée. Je suis sûr qu'une opération si banale ne devrait pas être difficile. Je ne suis pas sûr de ce qui me manque.Mettre en évidence un élément sélectionné dans React-Native FlatList

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, 
    }, 
}); 

Lorsque l'utilisateur tape sur un élément dans la liste, la méthode « onPress » est appelé avec les informations sur l'élément sélectionné. Mais la prochaine étape de l'élément de surbrillance dans Flatlist ne se produit pas. 'UnderlayColor' n'est d'aucune aide non plus.

Toute aide/conseil sera très apprécié.

+1

Vous devrez également modifier vos données (état), dans votre '' onPressAction' func remplacer setState' avec 'this.setState ({selectedItem : rowItem.id.value, data: {... this.state.data}}); 'Mais ce n'est pas recommandé. –

+0

J'ai essayé ça. N'a pas aidé –

Répondre

0

Je recommande à la place de this.state.selectedItem et réglage avec/vérification d'une rowItem.id.value, en utilisant un objet de la carte avec la clé: des paires de valeurs comme le montre la RN FlatList exemple docs: https://facebook.github.io/react-native/docs/flatlist.html. Jetez également un coup d'œil aux docs js Map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map. Le paramètre extraData recommandé par @ j.I-V garantira que le nouveau rendu se produira lorsque this.state.selected sera modifié lors de la sélection.

Votre onPressAction va évidemment changer un peu de l'exemple ci-dessous en fonction de si vous voulez limiter le nombre de sélections à un moment donné ou non permettre à l'utilisateur de basculer la sélection, etc.

En outre, bien que pas nécessaire par tout signifie, j'aime utiliser une autre classe ou un composant pur pour le composant renderItem; finit par regarder quelque chose comme ce qui suit:

export default class BasicFlatList extends Component { 
 
    state = { 
 
    otherStateStuff: ..., 
 
    selected: (new Map(): Map<string, boolean>) //iterable object with string:boolean key:value pairs 
 
    } 
 

 
    onPressAction = (key: string) => { 
 
    this.setState((state) => { 
 
     //create new Map object, maintaining state immutability 
 
     const selected = new Map(state.selected); 
 
     //remove key if selected, add key if not selected 
 
     this.state.selected.has(key) ? selected.delete(key, !selected.get(key)) : selected.set(key, !selected.get(key)); 
 
     return {selected}; 
 
    }); 
 
    } 
 

 
    renderRow = (item) => { 
 
    return (
 
     <RowItem 
 
      {...otherProps} 
 
      item={item} 
 
      onPressItem={this.onPressAction} 
 
      selected={!!this.state.selected.get(item.key)} /> 
 
    ); 
 
    } 
 

 
    render() { 
 
    return(
 
     <FlatList style={styles.container} 
 
     data={this.state.data} 
 
     renderItem={({ item }) => (
 
      this.renderRow(item) 
 
     )} 
 
     extraData={this.state} 
 
     /> 
 
    ); 
 
    } 
 
} 
 

 

 
class RowItem extends Component { 
 
    render(){ 
 
    //render styles and components conditionally using this.props.selected ? _ : _ 
 
    
 
    return (
 
     <TouchableOpacity> 
 
     ... 
 
     </TouchableOpacity> 
 
    ) 
 
    } 
 
}

0

Vous devez passer un accessoire extraData à votre FlatList afin qu'il rerender vos articles en fonction de votre sélection

ici:

<FlatList style={styles.container} 
    data={this.state.data} 
    extraData={this.state.selectedItem} 
    renderItem={({ item }) => (
     this.renderRow(item) 
    )} 
/> 

Source: https://facebook.github.io/react-native/releases/next/docs/flatlist.html

Assurez-vous que tout votre fonction renderItem dépend de est passé comme un prop (par exemple extraData) qui n'est pas === après les mises à jour, sinon votre interface ne peut pas mettre à jour sur les changements