Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React filter items with dropdown

I'm learning React and wanted to filter a list using a dropdown. I've almost got it but I can only click the drop down once and then the list will go empty. I'm pretty sure it's because I'm filtering the list and then it returns the list with the filtered items. But I'm not sure how to change that.

demo

var filterData = [
  { name: 'Matthew', sex: 'male' },
  { name: 'Amanda', sex: 'female' }
 ];
var FilterForm = React.createClass({
  getInitialState: function() {
    return {
      data: this.props.data,
      sex: ''
    }
  },
  handleChange: function(val) {
    // problem is here
    var filteredData = this.state.data.filter(function(item) {
      return item.sex === val;
    });
    this.setState({sex: val});
    this.setState({data: filteredData});
    console.log(filteredData);
  },
  render: function() {
    return ( 
      <div className="filter-form">
        <h1>Filter Form</h1>
        <FilterOptions data={this.state.data} changeOption={this.handleChange} /> 
        <FilterItems data={this.state.data} />
      </div>
    );
  }
});
var FilterOptions = React.createClass({
  getInitialState: function() {
    return {
      data: this.props.data,
      sex: ''
    }
  },
  handleChange: function(e) {
    var val = e.target.value;
    this.setState({bender: val});
    this.props.changeOption(val);
  },
  render: function() {
    return ( 
      <select id="sex" value={this.state.sex} onChange={this.handleChange}>
        <option value=""></option>
        <option value="male">male</option>
        <option value="female">female</option> 
      </select> 
    );
  }
});
var FilterItems = React.createClass({
  getInitialState: function() {
    return {
      data: this.props.data
    }
  },
  render: function() {
    return (
      <div className="filter-item">
        {this.props.data.map(function(item) {
          return ( 
            <div>{item.name}</div>
          );
        })}
      </div>
    );
  }
});
React.render( 
  <FilterForm data={filterData} />,
  document.getElementById('app')
);
like image 618
cocoa Avatar asked Nov 09 '15 16:11

cocoa


People also ask

How to create a dropdown select in ReactJS?

To create a dropdown select in React, use the react-select library. The react-select library has features dynamic search/filter, async option loading, accessibility, and fast render times. In addition, it has a flexible and beautiful Select Input control for ReactJS with multi-select, autocomplete, and ajax support.

How to display a dropdown menu of aquatic animals using React select?

Here is an example of modifying App.js to display a dropdown menu of aquatic animals: Add an array for aquaticCreatures and use the Select component provided by React Select: You will notice three things: You must import the Select component from react-select.

Can You filter options in a select menu in react?

However, there may be situations where a select menu can benefit from additional user experience niceties, like allowing a user to filter available choices. React Select is a highly configurable select menu library for React that features dynamic search and filter. It also supports async option loading, accessibility, and fast render times.

What is react select in react?

React Select is a highly configurable select menu library for React that features dynamic search and filter. It also supports async option loading, accessibility, and fast render times. In this tutorial, you will add React Select to a project.


2 Answers

Because your this.state.data is updated when you selected the drop-down at the first time. You should use this.props.data as the searching source You can change like this :

   handleChange: function(val) {
    this.setState({sex: val});
    var filteredData;
    if(val == ""){
      filteredData = this.props.data;
    }else{
      filteredData = this.props.data.filter(function(item) {
      return item.sex === val;
    });
    }
like image 124
Phi Nguyen Avatar answered Oct 12 '22 01:10

Phi Nguyen


There another consideration for your code as well: the only component that really needs state is the filterform. The other components only need props.

This can really simplify and reduce your code.

  • keep state in form only, and you only need to keep the selected filter in the state
  • pass the filter options + selected filter to your options component
  • pass the entire datalist + selected filter to your list component.

The following code also does exactly what you want (and reduces from 73 to 65 lines of code):

var data = [
      { name: 'Matthew', sex: 'male' },
      { name: 'Amanda', sex: 'female' }
     ];
    var FilterForm = React.createClass({
      getInitialState: function() {
        return {
          sex: ''
        }
      },
      handleChange: function(val) {
        this.setState({sex: val});
        console.log(val);
      },
      render: function() {
        // create list of options from input data (based on sex)
        var optionsArray=this.props.data.map((item) => { return item.sex });
        optionsArray.unshift("");
        return ( 
          <div className="filter-form">
            <h1>Filter Form</h1>
            <FilterOptions options={optionsArray} selected={this.state.sex} changeOption={this.handleChange} /> 
            <FilterItems data={this.props.data} filter={this.state.sex} />
          </div>
        );
      }
    });
    var FilterOptions = React.createClass({
      handleChange: function(e) {
        var val = e.target.value;
        this.props.changeOption(val);
      },
      render: function() {
        var selectedOption = this.props.selected;
        return ( 
          <select id="sex" value={selectedOption} onChange={this.handleChange}>
            {this.props.options.map(option => {
              return <option key={option} value={option} selected={(option.value == selectedOption)}>{option}</option>;
            })}
          </select> 
        );
      }
    });
    var FilterItems = React.createClass({
      render: function() {
        var filter = this.props.filter;
        var filteredData = this.props.data.filter((item) => {
          return (!filter || item.sex == filter)
        });

        return (
          <div className="filter-item">
            {filteredData.map(function(item) {
              return ( 
                <div>{item.name}</div>
              );
            })}
          </div>
        );
      }
    });
    React.render( 
      <FilterForm data={data} />,
      document.getElementById('app')
    );
like image 45
wintvelt Avatar answered Oct 12 '22 02:10

wintvelt