Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Create a Search Field in ReactJS

Tags:

reactjs

I'm new to react, and I'm working on a small project that uses a search bar to find data that I've gotten from my database.

The code for this component is below:

import React, { Component } from 'react';

class BodyData extends Component {
    state = {
        query: '',
        data: [],
    }

    handleInputChange = () => {
        this.setState({
            query: this.search.value
        })
        this.filterArray();
    }

    getData = () => {
        fetch(`http://localhost:4000/restaurants`)
        .then(response => response.json())
        .then(responseData => {
            // console.log(responseData)
            this.setState({
                data:responseData
            })
        })
    }

    filterArray = () => {
        var searchString = this.state.query;
        var responseData = this.state.data
        if(searchString.length > 0){
            // console.log(responseData[i].name);
            responseData = responseData.filter(l => {
                console.log( l.name.toLowerCase().match(searchString));
            })
        }
    }

    componentWillMount() {
        this.getData();
    }
    render() {
        return (
            <div className="searchForm">
                <form>
                    <input type="text" id="filter" placeholder="Search for..." ref={input => this.search = input} onChange={this.handleInputChange}/>
                </form>
                <div>
                    {
                        this.state.data.map((i) =>
                            <p>{i.name}</p>
                        )
                    }
                </div>
            </div>
        )
    }
}


export default BodyData;

So basically, I want to update the state as I type in the query text, and have the restaurant names I've mapped be reduced till a match is found.

From what I understood, this.state.data will be filtered as I type in my query in the search bar. However when I map out this.state.data, I get the whole list of restaurants instead of what I want to see.

Ive been through a bunch of tutes, and I'm not exactly sure how to go about doing that.

Can anyone help me with this please? Any other comments on the code are also welcome. I'm here to learn :)

Thank you!

like image 737
jerome Avatar asked Aug 07 '18 12:08

jerome


2 Answers

You could keep an additional piece of state called e.g. filteredData that contains all elements in data that include your query in the name, and then render that.

Example

class BodyData extends React.Component {
  state = {
    query: "",
    data: [],
    filteredData: []
  };

  handleInputChange = event => {
    const query = event.target.value;

    this.setState(prevState => {
      const filteredData = prevState.data.filter(element => {
        return element.name.toLowerCase().includes(query.toLowerCase());
      });

      return {
        query,
        filteredData
      };
    });
  };

  getData = () => {
    fetch(`http://localhost:4000/restaurants`)
      .then(response => response.json())
      .then(data => {
        const { query } = this.state;
        const filteredData = data.filter(element => {
          return element.name.toLowerCase().includes(query.toLowerCase());
        });

        this.setState({
          data,
          filteredData
        });
      });
  };

  componentWillMount() {
    this.getData();
  }

  render() {
    return (
      <div className="searchForm">
        <form>
          <input
            placeholder="Search for..."
            value={this.state.query}
            onChange={this.handleInputChange}
          />
        </form>
        <div>{this.state.filteredData.map(i => <p>{i.name}</p>)}</div>
      </div>
    );
  }
}
like image 82
Tholle Avatar answered Sep 22 '22 14:09

Tholle


Here is the code that will work for you

import React, { Component } from 'react';

class BodyData extends Component {

state = {
    query: '',
    data: [],
    searchString:[]
}

handleInputChange = (event) => {
    this.setState({
        query: event.target.value
    },()=>{
  this.filterArray();
})

}

getData = () => {
    fetch(`http://localhost:4000/restaurants`)
    .then(response => response.json())
    .then(responseData => {
        // console.log(responseData)
        this.setState({
            data:responseData,
            searchString:responseData
        })
    })
}

filterArray = () => {
    let searchString = this.state.query;
    let responseData = this.state.data;



    if(searchString.length > 0){
        // console.log(responseData[i].name);
        responseData = responseData.filter(searchString);
this.setState({
   responseData
})
    }

}

componentWillMount() {
    this.getData();
}
render() {
    return (
        <div className="searchForm">
            <form>
                <input type="text" id="filter" placeholder="Search for..."  onChange={this.handleInputChange}/>
            </form>
            <div>
                {
                    this.state.responseData.map((i) =>
                        <p>{i.name}</p>
                    )
                }
            </div>
        </div>
    )
  }
}


export default BodyData;

There are few changes which is needed.

  1. Set State is worked asynchronous.SO, to avoid it use arrow function when you need to do something immediately after set state.
  2. there are 2 different keyword in es6 instead of var. Let and Const . use them instead of var.
  3. There is no need of ref in input. you can directly get value of input by event.target.value

Enjoy Coding!!

like image 40
Pardeep Sharma Avatar answered Sep 21 '22 14:09

Pardeep Sharma