使用FlatList

时间:2017-08-14 02:42:04

标签: javascript reactjs react-native

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

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

到目前为止我在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组件来做这件事。

感谢您的帮助!

11 个答案:

答案 0 :(得分:14)

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

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

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

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

然后将noData bool传递给您的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>

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

如果有帮助,请告诉我!

答案 1 :(得分:6)

<强>更新 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
      })
    }
  }

答案 2 :(得分:2)

这是我的解决方法:

您需要备份数据

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时,它将更改为当前状态,并且无法再次更改。

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

答案 3 :(得分:2)

ref-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;

答案 4 :(得分:1)

对于有用的内存中搜索,您应该分别保存初始数据。

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

这种针对FlatList数据进行内存中搜索的解决方案,并使用它String.prototype .includes()方法搜索子字符串。

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

我的初始状态; <​​/ p>

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的数据源表达式;

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

快乐的编码...

答案 5 :(得分:0)

FYI data是要搜索的subtext,这是一种基本搜索,因为要搜索的数据被查看到数组的每个列表项中,是array/array的实际objects的副本,最后设置其状态,无论是否找到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
    });
  }

希望有帮助

答案 6 :(得分:0)

  

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

答案 7 :(得分:0)

在React Native中为列表视图数据创建搜索栏过滤器

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

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

class MyComponent extends React.Component 
  constructor() {
    // wrong retrun value from `foo()`, this.myProperty will be `Infinity`
    this.myProperty = foo();
  }

  // Component methods here....


  myFancyFunction() {
    // This code will encounter `Malformed calls from JS: field sizes are different`
    // `[xxxx, "<<Infinity>>", xxxxxxxxx, true]`
    this.timer = setInterval(() => {
      //Do something
    }, this.myProperty); //<-- should never be `Infinity` here
  }
}

Click Hear for more idea

答案 8 :(得分:0)

通过应用进行过滤

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

答案 9 :(得分:0)

就性能而言,这不是最佳的解决方案,但是如果您没有大量数据,请随时使用此功能:

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

答案 10 :(得分:0)

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

<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 是我的数据数组