quachhengtony
quachhengtony

Reputation: 135

How to search a FlatList via Search Bar React Native?

I have a React Native app built via Expo and I want add a search funstion to search a FlatList using a Search Bar in React Native. The search bar bellow is from React Native Paper.

This is my code (App.js):

constructor(props) {
    super(props);
    this.state = {
      dataSource: []
    }
  }

  state = {
    firstQuery: '',
  };

  componentDidMount() {
    const url = '// My URL'
    fetch(url)
    .then((response) => response.json())
    .then((responseJson) => {
      this.setState({
        dataSource: responseJson.product
      })
    })
    .catch((error) => {
      console.log(error)
    })
  }

  state = {
    search: '',
  };

  updateSearch = search => {
    this.setState({ search });
  };

  SearchFilterFunction(text) {
    const newData = this.dataSource.filter(function(item) {
      const itemData = item.name ? item.name.toUpperCase() : ''.toUpperCase();
      const textData = text.toUpperCase();
      return itemData.indexOf(textData) > -1;
    });
    this.setState({
      dataSource: newData,
      text: text,
    });
  }

render() {
    const { search } = this.state;
    const { firstQuery } = this.state;
    return (
      <Searchbar
        placeholder="Search"
        onChangeText={query => {text => this.SearchFilterFunction(text)}}
        value={firstQuery} />

        <FlatList
        data={this.state.dataSource}
        renderItem={this.renderItem} /> 

    );
  }
}

Do I need to set more default state? Is isLoading or error: null necessary? What am I doing wrong?

UPDATE This is my App.js now:

constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      text: '',
      dataSource: []
    }; 
    this.arrayholder = [];
  }

  state = {
    firstQuery: '',
  };

  componentDidMount() {
    const url = '// My URL'
    fetch(url)
    .then((response) => response.json())
    .then((responseJson) => {
      this.setState({
        isLoading: false,
        dataSource: responseJson.product
      }, {
        function() {
          this.arrayholder = responseJson;
        }
      }
      )
    })
    .catch((error) => {
      console.log(error)
    })
  }

  state = {
    search: '',
  };

  updateSearch = search => {
    this.setState({ search });
  };

  SearchFilterFunction(text) {
    const newData = this.dataSource.filter(function(item) {
      const itemData = item.name ? item.name.toUpperCase() : ''.toUpperCase();
      const textData = text.toUpperCase();
      return itemData.indexOf(textData) > -1;
    });
    this.setState({
      dataSource: newData,
      text: text,
    });
  }

  renderItem = ({item}) => {
    return (
       // Code
    );
  }

  render() {
    return (
      <Searchbar
        placeholder="Search"
        onChangeText={query => {text => this.SearchFilterFunction(text)}}
        value={this.state.text} />
    );
  }

It's giving me a 'Invariant Violation: Invalid argument passed as callback. Expected a function. Instead received: [object Object]'

Upvotes: 4

Views: 2457

Answers (2)

hong developer
hong developer

Reputation: 13906

When you search, you need a key to get it right. For example, if you search by address,

     <Searchbar
        placeholder="Search"
        onChangeText={{text => this.SearchFilterFunction(text)}}
        value={this.state.text} />

        <FlatList
        data={this.state.dataSource}
        renderItem={this.renderItem}
        keyExtractor={item => item.address}
        /> 

Upvotes: 1

Jaydeep Galani
Jaydeep Galani

Reputation: 4961

You need to tell flatlist that if something changes in ABC state variable then look for data change in source and re-render. Without this, it won't use new values.

So, to tell that you need to pass one prop extraData,

<FlatList
    extraData={this.state.dataSource}
    data={this.state.dataSource}
    renderItem={this.renderItem} /> 

Now if anything changes in dataSource, flatlist will re-render its content

Upvotes: 1

Related Questions