I have React components :
Main.jsx
import React from "react";
import { Products } from "../Products";
import { Filter } from "../Filter";
class Main extends React.Component {
state = {
products: [],
filteredProducts: [],
status: "all",
};
onFilterStatusChange = (status) => {
this.setState({ status });
};
componentDidMount() {
fetch("./products.json")
.then((responce) => responce.json())
.then((data) => this.setState({ products: Object.values(data) }));
}
filterProducts() {
this.setState(({ status }) => ({
filteredProducts:
status === "all"
? this.state.products
: this.state.products.filter((n) => n.prod_status?.includes(status)),
}));
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.status !== prevState.status ||
this.state.products !== prevState.products
) {
this.filterProducts();
}
}
render() {
return (
<main className="container content">
<Filter
values={[
"all",
"recommended",
"promotion",
"saleout",
"bestseller",
"new",
]}
value={this.state.status}
onChange={this.onFilterStatusChange}
/>
<Products products={this.state.filteredProducts} />
</main>
);
}
}
export { Main };
Filter.jsx
import statusMap from "../statusMap";
const Filter = ({ values, value, onChange }) => (
<div className="row filter_container">
<h3 className="filter_title">Sortować według</h3>
<div className="input-field col s12">
<select className="status_select">
{values.map((n) => (
<option onChange={() => onChange(n)} value={value === n} key={n}>
{statusMap.get(n)}
</option>
))}
</select>
</div>
</div>
);
export { Filter };
The problem is that the select does not respond to value changes, and therefore does not show the filtered products. I think I messed up with the properties
The filter used to work with type ="radio". After I tried to redo the filter (change type="radio" to ), he stopped working. This is what Filter.jsx looked like before changing to select:
{values.map((n) => (
<label>
<input
className="with-gap"
type="radio"
onChange={() => onChange(n)}
checked={value === n}
/>
<span>{statusMap.get(n)}</span>
</label>
))}
Please, help me fix this filter
CodePudding user response:
It worked with radio inputs because inputs handle directly the onChange event listener, if you want to use a select, you need to move the onChange on the select and use it like this:
<select className="status_select" onChange={(e) => onChange(e.target.value)}>
{values.map((n) => (
<option value={value} key={n}>
{statusMap.get(n)}
</option>
))}
</select>
You can check an example of how to handle a select properly here: demo.
CodePudding user response:
There are a few issues in your code:
- The
onChange
event is triggered on theselect
element, not on theoption
element. value={value === n}
, according to your code,value
is a string which I assume that represents the default value of theselect
, andn
is the current value inside the map function, meaning that the value property is a boolean, but you need it to be a unique value for each option. As for the default select value - in React you can use theselected
property- I also suggest you to use the index for the
key
property.
I made some tweaks to your code to try to fix your problem, or at least help you to find it. I can't test it as I don't have the statusMap
so its on you.
import React from "react";
class App extends React.Component {
state = {
products: [],
filteredProducts: [],
status: "all",
};
onFilterStatusChange = (status) => {
this.setState({ status });
};
componentDidMount() {
fetch("./products.json")
.then((responce) => responce.json())
.then((data) => this.setState({ products: Object.values(data) }));
}
filterProducts() {
this.setState(({ status }) => ({
filteredProducts:
status === "all"
? this.state.products
: this.state.products.filter((n) => n.prod_status?.includes(status)),
}));
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.status !== prevState.status ||
this.state.products !== prevState.products
) {
this.filterProducts();
}
}
render() {
return (
<main className="container content">
<Filter
values={[
"all",
"recommended",
"promotion",
"saleout",
"bestseller",
"new",
]}
value={this.state.status}
onFilterChange={this.onFilterStatusChange}
/>
<Products products={this.state.filteredProducts} />
</main>
);
}
}
export { App };
const Filter = ({ values, currentValue, onFilterChange }) => (
<div className='row filter_container'>
<h3 className='filter_title'>Sortować według</h3>
<div className='input-field col s12'>
<select
className='status_select'
onChange={(e) => onFilterChange(e.target.value)}
selected={currentValue}
>
{values.map((val, index) => (
<option value={val} key={index}>
{statusMap.get(val)}
</option>
))}
</select>
</div>
</div>
);