Reputation: 325
I need to use an input filter in React. I have a list of activities and need to filter them like filters on the picture. If the icons are unchecked, actions with these types of activities should not be showed. It works.
The problem that when I use input filter and write letters it works. But when I delete letter by letter nothing changes.
I understand that the problem is that I write the result in the state. And the state is changed.But how to rewrite it correctly.
const [activities, setActivities] = useState(allActivities);
const [value, setValue] = useState(1);
const [checked, setChecked] = useState<string[]>([]);
const switchType = (event: React.ChangeEvent<HTMLInputElement>)=> {
const currentIndex = checked.indexOf(event.target.value);
const newChecked = [...checked];
if (currentIndex === -1) {
newChecked.push(event.target.value);
} else {
newChecked.splice(currentIndex, 1);
}
//function that shows activities if they are checked or unchecked
setChecked(newChecked);
const res = allActivities.filter(({ type }) => !newChecked.includes(type));
setActivities(res);
};
//shows input filter
const inputSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
const foundItems = activities.filter(
(item) => item.activity.indexOf(event.target.value) > -1
);
setActivities(foundItems);
};
//shows participants filter
const countSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(Number(event.target.value));
const participantsSearch = allActivities.filter(
(item) => item.participants >= event.target.value
);
setActivities(participantsSearch);
};
This is render part
<Input
onChange={inputSearch}
startAdornment={
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
}
/>
<Input
onChange={countSearch}
type="number"
value={props.value}
startAdornment={
<InputAdornment
position="start"
className={classes.participantsTextField}
>
<PersonIcon />
</InputAdornment>
}
/>
Upvotes: 1
Views: 262
Reputation: 202864
The issue here is that you save over the state that you are filtering, so each time a filter is applied the data can only decrease in size or remain the same. It can never reset back to the full, unfiltered data.
Also with the way you've written the checkbox and input callbacks you can't easily mix the two.
Since the filtered data is essentially "derived" state from the allActivities
prop, and the value
and checked
state, it really shouldn't also be stored in state. You can filter allActivities
inline when rendering.
const [value, setValue] = useState<sting>('');
const [checked, setChecked] = useState<string[]>([]);
const switchType = (event: React.ChangeEvent<HTMLInputElement>)=> {
const currentIndex = checked.indexOf(event.target.value);
if (currentIndex === -1) {
setChecked(checked => [...checked, event.target.value]);
} else {
setChecked(checked => checked.filter((el, i) => i !== currentIndex);
}
};
const inputSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value.toLowerCase());
};
...
return (
...
{allActivites.filter(({ activity, type }) => {
if (activity || type) {
if (type) {
return checked.includes(type);
}
if (activity) {
return activity.toLowerCase().includes(value);
}
}
return true; // return all
})
.map(.....
Upvotes: 1
Reputation: 97
The problem lies with your inputSearch
code.
Each time you do setActivities(foundItems);
you narrow down the state of your activities
list. So when you start deleting, you don't see any change because you removed the rest of the activities from the state.
You'll want to take out allActivities
into a const, and always filter allActivities
in inputSearch
, like so:
const allActivities = ['aero', 'aeroba', 'aerona', 'aeronau'];
const [activities, setActivities] = useState(allActivities);
// ...rest of your code
const inputSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
const foundItems = allActivities.filter(
(item) => item.activity.indexOf(event.target.value) > -1
);
setActivities(foundItems);
};
// ...rest of your code
Upvotes: 0