简体   繁体   English

在 FlatList 上使用 React Native 搜索过滤器

[英]Search Filter with React Native on FlatList

I am trying to search through a flatlist based on a search bar text.我正在尝试根据搜索栏文本搜索平面列表。 The problem I am running into is that when the user mistypes...say they wanted to type "burger" but typed "burget" by mistake then it returns nothing as it should.我遇到的问题是,当用户输入错误时……说他们想输入“burger”,但错误地输入了“burget”,然后它应该返回任何内容。 When the user deletes the "t" then it should re-render the flatlist again with the last text matching the "burge" part.当用户删除“t”时,它应该再次重新渲染平面列表,最后一个文本与“burge”部分匹配。

note: using react-native-elements search bar which allows me to call the text with just e or event.注意:使用 react-native-elements 搜索栏,它允许我只用 e 或 event 调用文本。

What I have so far in the Main.js file:到目前为止,我在 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>

then the TruckList.JS:然后是 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>
        )
      }
    }

I have tried a few other ways to no avail.我尝试了其他几种方法都无济于事。 Also the only solutions I have seen working for React Native are with ListView which will be depreciated in time.此外,我看到的唯一适用于 React Native 的解决方案是使用 ListView,它会及时贬值。 So I am trying to do this with the new FlatList Component.所以我正在尝试使用新的 FlatList 组件来做到这一点。

Thanks for your help!谢谢你的帮助!

I came across this same issue today when trying to implement a filter / search function on the new FlatList component.我今天在尝试在新的 FlatList 组件上实现过滤器/搜索功能时遇到了同样的问题。 This is how I managed to solve it:这就是我设法解决它的方法:

By creating another item in the state of the parent component called noData, you can set that to true when there are no results that match your search and then render your FlatList conditionally.通过在父组件的状态中创建另一个名为 noData 的项目,您可以在没有与您的搜索匹配的结果时将其设置为 true,然后有条件地呈现您的 FlatList。

My implementation is slightly different to yours, but if I had to adjust your code it would look something like this:我的实现与你的略有不同,但如果我必须调整你的代码,它看起来像这样:

Searchtext function:搜索文本功能:

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

Then pass the noData bool to your TruckList component:然后将 noData bool 传递给您的 TruckList 组件:

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

Then render your FlatList in the TruckList component only if there are results:然后仅在有结果时才在 TruckList 组件中呈现您的 FlatList:

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

That should then take care of handling user typing errors - as it will re-render the flatlist as soon as there are no results, and will remember the previous search state when you remove the typing error..然后应该处理用户输入错误 - 因为它会在没有结果时立即重新呈现平面列表,并且在您删除输入错误时会记住以前的搜索状态。

Let me know if that helps!如果这有帮助,请告诉我!

For a useful in-memory search you should keep initial data seperately.对于有用的内存搜索,您应该单独保留初始数据。

I have more simple solution for this.我有更简单的解决方案。

This solution for in-memory search on FlatList's data and uses it String.prototype​.includes() method to search substring.此解决方案用于对 FlatList 的数据进行内存搜索,并使用它的 String.prototype .includes() 方法来搜索子字符串。

You can find full source code of this component in this gist;您可以在此要点中找到该组件的完整源代码; https://gist.github.com/metehansenol/46d065b132dd8916159910d5e9586058 https://gist.github.com/metehansenol/46d065b132dd8916159910d5e9586058

My initial state;我的初始状态;

this.state = {
  searchText: "",
  data: [],
  filteredData: []
};

My SearchBar component (it comes from react-native-elements package);我的 SearchBar 组件(它来自 react-native-elements 包);

<SearchBar
  round={true}
  lightTheme={true}
  placeholder="Search..."
  autoCapitalize='none'
  autoCorrect={false}
  onChangeText={this.search}
  value={this.state.searchText}
/>

My search method;我的搜索方法;

search = (searchText) => {
  this.setState({searchText: searchText});

  let filteredData = this.state.data.filter(function (item) {
    return item.description.includes(searchText);
  });

  this.setState({filteredData: filteredData});
};

And last my FlatList's DataSource expression;最后是我的 FlatList 的 DataSource 表达式;

<FlatList
  data={this.state.filteredData && this.state.filteredData.length > 0 ? this.state.filteredData : this.state.data}
  keyExtractor={(item) => `item-${item.id}`}
  renderItem={({item}) => <ListItem
    id={item.id}
    code={item.code}
    description={item.description}
  />}
/>

Happy coding...快乐编码...

Update: This blog can help you better understand the searching in a FlatList.更新: 这个博客可以帮助你更好地理解在 FlatList 中的搜索。

FYI: If you have huge online data then you can also use algolia .仅供参考:如果您有大量的在线数据,那么您也可以使用algolia

I adjusted the above code for me in order to make it work properly.我为我调整了上面的代码以使其正常工作。 The reason is that when user removes the last wrong character, code search this new string from a previous search list (state) which does not contain all objects, although it had to search from a full list available.原因是当用户删除最后一个错误字符时,代码会从不包含所有对象的先前搜索列表(状态)中搜索这个新字符串,尽管它必须从可用的完整列表中进行搜索。 So, I have two list now.所以,我现在有两个清单。 One contains full list of objects and second contains only rendered list of objects which is changing upon search.第一个包含对象的完整列表,第二个只包含在搜索时更改的呈现对象列表。

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

Here is my solution:这是我的解决方案:

You need to have a backup of your data您需要备份数据

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

on search method关于搜索方法

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

Explanation: when calling setState on your data it will changed to current state and cannot be changed again.说明:当对您的数据调用 setState 时,它​​将更改为当前状态并且无法再次更改。

So backup data will handle to filter your data.因此备份数据将处理过滤您的数据。

Make Search Bar Filter for List View Data in React Native在 React Native 中为列表视图数据制作搜索栏过滤器

For Real-Time Searching in List View using Search Bar Filter使用搜索栏过滤器在列表视图中实时搜索

  • We will load the list from the network call and then show it to the user.我们将从网络调用中加载列表,然后将其显示给用户。
  • The user can search the data by entering the text in TextInput.用户可以通过在 TextInput 中输入文本来搜索数据。
  • After inserting the text SearchFilterFunction will be called We will compare the list data with the inserted data and will make a new Data source.插入文本后将调用 SearchFilterFunction 我们将列表数据与插入的数据进行比较,并将创建一个新的数据源。
  • We will update the data source attached to the ListView.我们将更新附加到 ListView 的数据源。
  • It will re-render the list and the user will be able to see the filtered data.它将重新呈现列表,用户将能够看到过滤后的数据。

 //This is an example code to Add Search Bar Filter on Listview// import React, { Component } from 'react'; //import react in our code. import { Text, StyleSheet, View, FlatList, TextInput, ActivityIndicator, Alert, } from 'react-native'; //import all the components we are going to use. export default class App extends Component { constructor(props) { super(props); //setting default state this.state = { isLoading: true, text: '' }; this.arrayholder = []; } componentDidMount() { return fetch('https://jsonplaceholder.typicode.com/posts') .then(response => response.json()) .then(responseJson => { this.setState( { isLoading: false, dataSource: responseJson }, function() { this.arrayholder = responseJson; } ); }) .catch(error => { console.error(error); }); } SearchFilterFunction(text) { //passing the inserted text in textinput const newData = this.arrayholder.filter(function(item) { //applying filter for the inserted text in search bar const itemData = item.title ? item.title.toUpperCase() : ''.toUpperCase(); const textData = text.toUpperCase(); return itemData.indexOf(textData) > -1; }); this.setState({ //setting the filtered newData on datasource //After setting the data it will automatically re-render the view dataSource: newData, text: text, }); } ListViewItemSeparator = () => { //Item sparator view return ( <View style={{ height: 0.3, width: '90%', backgroundColor: '#080808', }} /> ); }; render() { if (this.state.isLoading) { //Loading View while data is loading return ( <View style={{ flex: 1, paddingTop: 20 }}> <ActivityIndicator /> </View> ); } return ( //ListView to show with textinput used as search bar <View style={styles.viewStyle}> <TextInput style={styles.textInputStyle} onChangeText={text => this.SearchFilterFunction(text)} value={this.state.text} underlineColorAndroid="transparent" placeholder="Search Here" /> <FlatList data={this.state.dataSource} ItemSeparatorComponent={this.ListViewItemSeparator} renderItem={({ item }) => ( <Text style={styles.textStyle}>{item.title}</Text> )} enableEmptySections={true} style={{ marginTop: 10 }} keyExtractor={(item, index) => index.toString()} /> </View> ); } } const styles = StyleSheet.create({ viewStyle: { justifyContent: 'center', flex: 1, marginTop: 40, padding: 16, }, textStyle: { padding: 10, }, textInputStyle: { height: 40, borderWidth: 1, paddingLeft: 10, borderColor: '#009688', backgroundColor: '#FFFFFF', }, });

Click Hear for more idea 单击“聆听”了解更多想法

ref - https://medium.freecodecamp.org/how-to-build-a-react-native-flatlist-with-realtime-searching-ability-81ad100f6699参考 - https://medium.freecodecamp.org/how-to-build-a-react-native-flatlist-with-realtime-searching-ability-81ad100f6699

constructor(props) {
super(props);
this.state = {
  data: [],
  value: ""
};

this.arrayholder = [];
}

Next fetching data :-下一个获取数据:-

_fetchdata = async () => {
const response = await fetch("https://randomuser.me/api?results=10");
const json = await response.json();
this.setState({ data: json.results });

this.arrayholder = json.results;
};

Next define searchFilterFunction :-接下来定义 searchFilterFunction :-

searchFilterFunction = text => {
this.setState({
  value: text
});


const newData = this.arrayholder.filter(item => {
  const itemData = item.email.toLowerCase();

  const textData = text.toLowerCase();

  return itemData.indexOf(textData) > -1;
});

this.setState({ data: newData });
};

rendering searchView:-呈现搜索视图:-

    <TextInput
      style={{ height: 40, borderColor: "gray", borderWidth: 1 }}
      onChangeText={text => this.searchFilterFunction(text)}
    />

Don't forget to import TextInput from "react-native";不要忘记从“react-native”导入 TextInput;

You can Search your data by following these steps :您可以按照以下步骤搜索您的数据:

<TextInput onChangeText={(text) => searchData(text)} value={input} />
***Please Note *searchData is my function whom I passing a text prop*** 
const searchData = (text) => {
    const newData = restaurantsData.filter((item) => {
        return item.title.search(text) > -1;
    });
    setRestaurantsData(newData);
    setInput(text);
};

Note RestaurantsData is my data array注意 RestaurantData 是我的数据数组

FYI : data is the subtext to be searched, this is a basic search implemented as the data to be searched is looked into every list item of an array which is a copy of the actual array/array of objects and finally its state is set whether match found or not between 0 to ( actualArray.length-1 ) and the temporary arrayData is rendered if there is at least one match else actualArray is rendered仅供参考data是要搜索的subtext ,这是一个基本搜索,因为要搜索的数据会查看数组的每个列表项,该数组是实际array/array objects array/array的副本,最后设置其状态是否在0到( actualArray.length-1 )之间找到匹配或不匹配,如果至少有一个匹配,则呈现临时arrayData ,否则呈现actualArray

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

Hope this helps希望这有帮助

My search method;我的搜索方法; from @metehan-senol来自@metehan-senol

search = (searchText) => {
 this.setState({searchText: searchText});

 let filteredData = this.state.data.filter(function (item) {
   return item.description.includes(searchText);
 });

 this.setState({filteredData: filteredData});
};

the search method of could be simplify and Eslint proof like so的搜索方法可以像这样简化和Eslint证明

search = (searchText) => {
  const searched = searchText.toLowerCase();
  this.setState(prevState => ({
    searchText: searched,
    filteredData: prevState.data.filter(item =>
      item.description.toLowerCase().includes(searched)
    ),
  }));
}; 

Do filter by applying通过应用过滤

let filterData= data.filter((item) => {
  return item.name.toLowerCase().match(text)
})
if (!text || text === '') {
  this.setState({
    datasource: initial
  })
} else if (!Array.isArray(filterData) && !filterData.length) {
  // set no data flag to true so as to render flatlist conditionally
  this.setState({
    noData: true
  })
} else if (Array.isArray(filterData)) {
  this.setState({
    noData: false,`enter code here`
    dataSource: filterData
  })`enter code here`
}

This is not the best solution in terms of performance, but if you do not have a large amount of data, then feel free to use this function:就性能而言,这不是最好的解决方案,但是如果您没有大量数据,那么可以随意使用此功能:

  searchFilter () {
    return this.props.data.filter((item) => {
       const regex = new RegExp(this.state.searchInput, "gi")
       return item.label.match(regex);
    })
  }

And then in your FlatList component:然后在您的 FlatList 组件中:

  <FlatList
    data={this.searchFilter()}
    renderItem={this.renderItem}
    keyExtractor={(item) => item.value}
  />

const SearchUser = (e) =>{ console.log(e) const setProject = Project.filter(item => item.name.toLowerCase().includes(e.toLowerCase()) ) console.log(setProject) setfetch(setProject) } const SearchUser = (e) =>{ console.log(e) const setProject = Project.filter(item => item.name.toLowerCase().includes(e.toLowerCase()) ) console.log(setProject) setfetch(设置项目)}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM