How to Filter an Array onClick in React
I Am Trying to Filter an Array of Coffee Based on Its Origin via a Button Click in React. Right Now, Whenever a Button Is Clicked the Array Goes to 0 Instead...
I am trying to filter an array of coffee based on its origin via a button click in React. Right now, whenever a button is clicked the array goes to 0 instead of the desired result of however many items contain the origin clicked. Thanks for your help. Feel free to critique my code as well - I am just beginning!
class Coffee extends React.Component {
constructor() {
super();
this.state = { coffees: [
{
name: 'Banko',
origin: 'Ethiopia',
price: 16
},
{
name: 'Pueblo',
origin: 'Costa Rica',
price: 14
},
{
name: 'Don Pablo',
origin: 'Columbia',
price: 13
},
{
name: 'Hava Lama',
origin: 'Columbia',
price: 15
},
{
name: 'Guillermo Salva',
origin: 'Ethiopia',
price: 19
},
{
name: 'Salla Rosa',
origin: 'Kenya',
price: 20
},
{
name: 'Santor Gustavio',
origin: 'Panama',
price: 25
}
]
}
}
handleClick = event => {
const byOrigin = event.target.value
const filterCoffee = this.state.coffees.filter(coffee => coffee[origin] === [byOrigin])
this.setState({coffees: filterCoffee})
}
render() {
const renderAll = this.state.coffees.map(coffee => <li key={Date.now()}>{coffee.name}</li>)
return (
<div>
<button value='all' onClick={this.handleClick}>All</button>
<button value='Ethiopia' onClick={this.handleClick}>Ethiopia</button>
<button value='Costa Rica' onClick={this.handleClick}>Costa Rica</button>
<button value='Kenya' onClick={this.handleClick}>Kenya</button>
<button value='Columbia' onClick={this.handleClick}>Columbia</button>
<button value='Panama' onClick={this.handleClick}>Panama</button>
<p>Coffee: {renderAll}</p>
<p>{this.state.coffees.length}</p>
</div>
)
}
}
ReactDOM.render(<Coffee />, document.getElementById('root'))
3 Answers
You can check like this, please try this.
this.state.coffees.filter(coffee => coffee['origin'] === byOrigin)
Optimized way
const buttons = [
{ name: "All", value: "All" },
{ name: "Ethiopia", value: "Ethiopia" },
{ name: "Costa Rica", value: "Costa Rica" },
{ name: "Kenya", value: "Kenya" },
{ name: "Columbia", value: "Columbia" },
{ name: "Panama", value: "Panama" }
];
define button in loop for optimization
{buttons.map(({ name, value }) => (
<button
key={name}
value={value}
onClick={this.handleClick.bind(this, name)}
>
{name}
</button>
))}
Complete code
const buttons = [
{ name: "All", value: "All" },
{ name: "Ethiopia", value: "Ethiopia" },
{ name: "Costa Rica", value: "Costa Rica" },
{ name: "Kenya", value: "Kenya" },
{ name: "Columbia", value: "Columbia" },
{ name: "Panama", value: "Panama" }
];
class Coffee extends React.Component {
constructor() {
super();
this.state = {
coffees: [
{
name: "Banko",
origin: "Ethiopia",
price: 16
},
{
name: "Pueblo",
origin: "Costa Rica",
price: 14
},
{
name: "Don Pablo",
origin: "Columbia",
price: 13
},
{
name: "Hava Lama",
origin: "Columbia",
price: 15
},
{
name: "Guillermo Salva",
origin: "Ethiopia",
price: 19
},
{
name: "Salla Rosa",
origin: "Kenya",
price: 20
},
{
name: "Santor Gustavio",
origin: "Panama",
price: 25
}
],
filterCoffee: []
};
}
componentDidMount() {
this.setState({
filterCoffee: this.state.coffees
});
}
handleClick = name => {
let filterCoffee = [];
if (name === "All") {
filterCoffee = this.state.coffees;
} else {
filterCoffee = this.state.coffees.filter(
coffee => coffee.origin === name
);
}
this.setState({ filterCoffee });
};
render() {
const renderAll = this.state.filterCoffee.map(coffee => (
<li key={coffee.name}>{coffee.name}</li>
));
return (
<div>
{buttons.map(({ name, value }) => (
<button
key={name}
value={value}
onClick={this.handleClick.bind(this, name)}
>
{name}
</button>
))}
<p>Coffee: {renderAll}</p>
<h2>{this.state.filterCoffee.length}</h2>
</div>
);
}
}
You should have a separate array of original coffees. On component mount, you must copy your original array into another array and use that array further.
this.state = {
coffees: [{
name: 'Banko',
origin: 'Ethiopia',
price: 16
},
{
name: 'Pueblo',
origin: 'Costa Rica',
price: 14
},
{
name: 'Don Pablo',
origin: 'Columbia',
price: 13
},
{
name: 'Hava Lama',
origin: 'Columbia',
price: 15
},
{
name: 'Guillermo Salva',
origin: 'Ethiopia',
price: 19
},
{
name: 'Salla Rosa',
origin: 'Kenya',
price: 20
},
{
name: 'Santor Gustavio',
origin: 'Panama',
price: 25
}
],
filterCoffee: [] //create another array
}
On component mount copy original array to a temparary array
componentDidMount(){
this.setState({
filterCoffee: this.state.coffees
})
}
Now use filterCoffee to render
const renderAll = this.state.filterCoffee.map(coffee => <li key={coffee.name}>{coffee.name}</li>)
Finally on click you must check the condition when you click on all button,
handleClick = event => {
const byOrigin = event.target.value
let filterCoffee = []
if(event.target.value === 'all'){
//If clicked on all button copy the original array as it is
filterCoffee = this.state.coffees
} else{
// If clicked on any other button filter the original array based on value
filterCoffee = this.state.coffees.filter(coffee => coffee.origin === byOrigin)
}
this.setState({filterCoffee})
}