web-dev-qa-db-fra.com

Filtre de recherche avec React Native sur FlatList

J'essaye de rechercher par une flatlist basée sur un texte de barre de recherche. Le problème que je rencontre est que lorsque l'utilisateur utilise des fautes de frappe ... il dit qu'il voulait saisir "burger" mais tapé "burget" par erreur, il ne renvoie rien comme il se doit. Lorsque l'utilisateur supprime le "t", il doit alors restituer à nouveau la liste standard avec le dernier texte correspondant à la partie "renverser".

remarque: en utilisant la barre de recherche react-native-elements qui me permet d’appeler le texte avec e ou event.

Ce que j'ai jusqu'à présent dans le fichier Main.js:

searchText = (e) => {
    let text = e.toLowerCase();
    let trucks = this.state.data;

    // search by food truck name
    let filteredName = trucks.filter((truck) => {
      return truck.name.toLowerCase().match(text); 
    });

    // if no match and text is empty
    if(!text || text === '') {
      console.log('change state');
        this.setState({
          data: initial
        });
      }
    // if no name matches to text output
    else if(!Array.isArray(filteredName) && !filteredName.length) {
      console.log("not name");
      this.setState({
        data: [],
      });
    }
    // if name matches then display
    else if(Array.isArray(filteredName)) {
      console.log('Name');
      this.setState({
        data: filteredName,
      });
    }
   };

<View style={styles.container}>
  <SearchBar
    round
    lightTheme
    containerStyle={styles.search}
    ref="search"
    textInputRef="searchText"
    onChangeText={this.searchText.bind(this)}
    placeholder='Search by Truck Name...'
   />
   <TruckList getTruck={(truck) => this.setTruck(truck)} truckScreen={this.truckScreen} data={this.state.data}/>
</View>

puis le TruckList.JS:

export default class TruckList extends Component {
    // rendering truck screen
    renderTruckScreen = (item) => {
        this.props.truckScreen();
        this.props.getTruck(item);
    }

    render() {
        return(
            <List style={styles.list}>
                <FlatList
                    data={this.props.data}
                    renderItem={({ item }) => (
                        <ListItem
                            roundAvatar
                            avatar={{uri: item.pic1}}
                            avatarStyle={styles.avatar}
                            title={item.name}
                            titleStyle={styles.title}
                            subtitle={
                                <View style={styles.subtitleView}>
                                    <Text style={styles.subtitleFood}>{item.food}</Text>
                                    <View style={styles.subtitleInfo}>
                                        <Icon 
                                            name="favorite"
                                            size={20}
                                            color={"#f44336"}
                                            style={styles.subtitleFavorite}
                                        />
                                        <Text style={styles.subtitleFavoriteText}>{item.favorited} favorited</Text>
                                    </View>
                                </View>
                            }
                            onPress={() => this.renderTruckScreen(item)}
                        />
                    )}
                    keyExtractor={(item) => item.uid}
                    ListFooterComponent={this.footer}
                />
            </List>
        )
      }
    }

J'ai essayé quelques autres façons en vain. De plus, les seules solutions que j'ai vues travailler pour React Native sont celles de ListView, qui seront amorties avec le temps. J'essaie donc de faire cela avec le nouveau composant FlatList.

Merci de votre aide!

7
T. Evans

Je suis tombé sur le même problème aujourd'hui en essayant d'implémenter une fonction de filtrage/recherche sur le nouveau composant FlatList. Voici comment j'ai réussi à le résoudre:

En créant un autre élément dans l'état du composant parent appelé noData, vous pouvez le définir sur true lorsqu'il n'y a aucun résultat correspondant à votre recherche, puis restituer votre FlatList de manière conditionnelle.

Mon implémentation est légèrement différente de la vôtre, mais si je devais ajuster votre code, il ressemblerait à ceci:

Fonction Searchtext:

searchText = (e) => {
    let text = e.toLowerCase()
    let trucks = this.state.data
    let filteredName = trucks.filter((item) => {
      return item.name.toLowerCase().match(text)
    })
    if (!text || text === '') {
      this.setState({
        data: initial
      })
    } else if (!Array.isArray(filteredName) && !filteredName.length) {
      // set no data flag to true so as to render flatlist conditionally
      this.setState({
        noData: true
      })
    } else if (Array.isArray(filteredName)) {
      this.setState({
        noData: false,
        data: filteredName
      })
    }
  }

Puis passez le noData bool à votre composant TruckList: 

<TruckList getTruck={(truck) => this.setTruck(truck)} 
truckScreen={this.truckScreen} data={this.state.data} noData={this.state.noData}/>

Rendez ensuite votre FlatList dans le composant TruckList uniquement s'il y a des résultats: 

<List style={styles.list}>
{this.props.noData ? <Text>NoData</Text> : <FlatList {...} />}         
</List>

Cela devrait alors prendre en charge le traitement des erreurs de frappe des utilisateurs - car il rendra à nouveau la liste plate dès qu’il n’y aura aucun résultat, et se souviendra de l’état de la recherche précédent lorsque vous supprimerez l’erreur de frappe. 

Dis moi si ça aide!

13
jeanverster

Mise à jour:Ce blog peut vous aider à mieux comprendre la recherche dans une FlatList.

FYI: Si vous avez d’énormes données en ligne, vous pouvez également utiliser algolia .

J'ai ajusté le code ci-dessus pour que cela fonctionne correctement. La raison en est que lorsque l'utilisateur supprime le dernier caractère incorrect, le code recherche cette nouvelle chaîne dans une liste de recherche précédente (état) qui ne contient pas tous les objets, bien qu'il ait dû effectuer une recherche dans une liste complète disponible. Donc, j'ai deux liste maintenant. Le premier contient la liste complète des objets et le second ne contient que la liste rendue des objets qui est modifiée lors de la recherche.

handleSearchInput(e){
    let text = e.toLowerCase()
    let fullList = this.state.fullListData;
    let filteredList = fullList.filter((item) => { // search from a full list, and not from a previous search results list
      if(item.guest.fullname.toLowerCase().match(text))
        return item;
    })
    if (!text || text === '') {
      this.setState({
        renderedListData: fullList,
        noData:false,
      })
    } else if (!filteredList.length) {
     // set no data flag to true so as to render flatlist conditionally
       this.setState({
         noData: true
       })
    }
    else if (Array.isArray(filteredList)) {
      this.setState({
        noData: false,
        renderedListData: filteredList
      })
    }
  }
6
Faisal Hassan

Voici ma solution:

Vous devez avoir une sauvegarde de vos données

this.state = {
    data: [],
    backup: []
}

sur la méthode de recherche

search = txt => {
    let text = txt.toLowerCase()
    let tracks = this.state.backup
    let filterTracks = tracks.filter(item => {
    if(item.name.toLowerCase().match(text)) {
      return item
    }
  })
  this.setState({ data: filterTracks })
}

Explication: lorsque vous appelez setState sur vos données, il passe à l'état actuel et ne peut plus être modifié.

Les données de sauvegarde se chargeront donc de filtrer vos données.

1
Jundell

FYI: data est la subtext à rechercher, il s'agit d'une recherche de base implémentée car les données à rechercher sont examinées dans chaque élément de la liste d'un tableau qui est une copie du array/array réel de objects et finalement l'état est défini, que la correspondance trouvée ou non entre 0 à (actualArray.length-1) et que la variable temporaire arrayData soit rendue s'il existe au moins une correspondance, sinon la variable actualArray est rendue

implementSearch(data) {
    temp = [];
    var count = 0;
    var searchData = data.toUpperCase();
    var arr = this.state.personDetail;
    for (var i = 0; i < arr.length; i++) {
      var actualData = arr[i].name.toUpperCase();
      if (actualData.includes(searchData)) {
        temp.Push(arr[i]);
        count++;
      }
    }
    this.setState({
      tempArray: temp,
      matches: count,
      searchValue: data
    });
  }

Espoir cela aide

0
Mohit Kumar