【问题标题】:Search Filter with React Native on FlatList在 FlatList 上使用 React Native 搜索过滤器
【发布时间】:2017-08-14 02:42:03
【问题描述】:

我正在尝试根据搜索栏文本搜索平面列表。我遇到的问题是,当用户输入错误......说他们想输入“burger”但错误地输入了“burget”时,它不会返回任何内容。当用户删除“t”时,它应该使用与“burge”部分匹配的最后一个文本再次重新呈现平面列表。

注意:使用 react-native-elements 搜索栏,它允许我只用 e 或 event 调用文本。

到目前为止我在 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>

然后是 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>
        )
      }
    }

我尝试了其他几种方法都无济于事。此外,我见过的为 React Native 工作的唯一解决方案是使用 ListView,它会及时贬值。所以我试图用新的 FlatList 组件来做到这一点。

感谢您的帮助!

【问题讨论】:

  • 有什么问题?用户修改搜索文本时是否不会重新渲染?
  • @Umesh 问题在于,当用户输入错误时,数据被设置为[],然后当他们删除错误输入时,数据应重置回搜索的最后状态......只是还没有弄清楚它是如何工作的。可能设置以前的状态然后以某种方式调用它?
  • 当用户输入错误时,你的结果是空的 [ ] 但是当用户更正它时,它不会再次获取结果吗?我猜onChange,你每次都会得到结果。
  • 它应该再次获取结果,但是它没有。错误类型将数据设置为[],但是当您删除错误类型时,数据仍然是[]。当我在键入过程中进行控制台日志时,在删除错误类型后会发生什么情况,它会返回到 else if(Array.isArray(filteredName)) 但是,没有数据用于将状态重置为或类似的东西
  • 可能你需要调整你的条件顺序。我的意见是搜索并存储每次文本搜索更改的结果,而不是依赖以前的结果集。

标签: javascript reactjs react-native


【解决方案1】:

我今天尝试在新的 FlatList 组件上实现过滤器/搜索功能时遇到了同样的问题。这就是我设法解决它的方法:

通过在名为 noData 的父组件的状态下创建另一个项,您可以在没有与您的搜索匹配的结果时将其设置为 true,然后有条件地呈现您的 FlatList。

我的实现与你的略有不同,但如果我不得不调整你的代码,它看起来像这样:

搜索文本功能:

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

然后将 noData 布尔值传递给 TruckList 组件:

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

然后只有在有结果的情况下才在 TruckList 组件中渲染你的 FlatList:

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

这应该负责处理用户输入错误 - 因为它会在没有结果时重新呈现平面列表,并且会在您删除输入错误时记住之前的搜索状态..

如果有帮助,请告诉我!

【讨论】:

  • 你们有这个解决方案的 github 链接吗?
  • 不适合我,当我在做 Trucks.filter((item) => {console.log(item) } 的控制台时,它会给出“消息:“项目未定义”“
  • 在 item.name.toLowerCase() 中也出现错误
  • 如果您在控制台记录您正在过滤的数据,您会在其中获得任何数据吗?
  • 真的需要通过this.props.noData吗?检查if(this.props.data) 会不会更干净
【解决方案2】:

对于有用的内存搜索,您应该单独保留初始数据。

对此我有更简单的解决方案。

此解决方案用于在 FlatList 的数据上进行内存搜索,并使用它的 String.prototype​.includes() 方法来搜索子字符串。

您可以在此 gist 中找到该组件的完整源代码; https://gist.github.com/metehansenol/46d065b132dd8916159910d5e9586058

我的初始状态;

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

我的 SearchBar 组件(它来自 react-native-elements 包);

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

我的搜索方法;

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

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

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

最后是我的 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}
  />}
/>

编码愉快...

【讨论】:

    【解决方案3】:

    更新: This blog 可以帮助您更好地理解 FlatList 中的搜索。

    仅供参考: 如果您有大量在线数据,也可以使用algolia

    我为我调整了上面的代码以使其正常工作。原因是当用户删除最后一个错误字符时,代码会从不包含所有对象的先前搜索列表(状态)中搜索这个新字符串,尽管它必须从可用的完整列表中搜索。所以,我现在有两个清单。一个包含完整的对象列表,第二个仅包含在搜索时更改的渲染对象列表。

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

    【讨论】:

      【解决方案4】:

      这是我的解决方案:

      您需要备份您的数据

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

      关于搜索方法

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

      说明:当对你的数据调用 setState 时,它​​会变为当前状态,并且不能再次更改。

      因此备份数据将处理过滤您的数据。

      【讨论】:

        【解决方案5】:

        为 React Native 中的列表视图数据制作搜索栏过滤器

        使用搜索栏过滤器在列表视图中进行实时搜索

        • 我们将从网络调用中加载列表,然后将其显示给用户。
        • 用户可以通过在 TextInput 中输入文本来搜索数据。
        • 插入文本后会调用 SearchFilterFunction 我们将 将列表数据与插入的数据进行比较,并将创建一个新数据 来源。
        • 我们将更新附加到 ListView 的数据源。
        • 它将重新呈现列表,用户将能够看到 过滤后的数据。

        //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

        【讨论】:

          【解决方案6】:

          参考-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 = [];
          }
          

          下一步获取数据:-

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

          接下来定义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 });
          };
          

          渲染 searchView:-

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

          别忘了从“react-native”导入TextInput;

          【讨论】:

            【解决方案7】:

            您可以按照以下步骤搜索您的数据:

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

            注意 RestaurantsData 是我的数据数组

            【讨论】:

              【解决方案8】:

              仅供参考data 是要搜索的 subtext,这是一个基本搜索,因为要搜索的数据会查看数组的每个列表项,该数组是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
                  });
                }

              希望这有帮助

              【讨论】:

                【解决方案9】:

                我的搜索方法;来自@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});
                };
                

                的搜索方法可以像这样简化和Eslint证明

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

                【讨论】:

                  【解决方案10】:

                  通过应用进行过滤

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

                  【讨论】:

                    【解决方案11】:

                    这不是性能上最好的解决方案,但是如果你没有大量的数据,那么可以随意使用这个功能:

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

                    然后在你的 FlatList 组件中:

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

                    【讨论】:

                      猜你喜欢
                      • 2019-11-26
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-09-14
                      • 1970-01-01
                      • 2017-06-24
                      相关资源
                      最近更新 更多