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')
);
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')
);
Share
Improve this question
asked Nov 9, 2015 at 16:20
cocoacocoa
3,9217 gold badges31 silver badges57 bronze badges
2 Answers
Reset to default 8Because 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;
});
}
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')
);