I’m wanting to do something fairly simple in needing to filter a number of products in my React project. The array of filters (an array of strings) is stored in State. By default the array contains ["All"] until another filter is clicked and this is replaced by that filter name. I can add filter strings okay to the array but in removing them they don’t seem to be removed from the array.
I am making a copy of the array to avoid mutation but not sure if I’m doing it right? I had it working without making a copy but then wanted to test if the array was empty. As the page hadn’t rendered yet I was getting the old value of the array. I wasn’t sure of the best way to approach it? Any guidance would be much appreciated.
function FilterGroup({ filterData }) {
const [ filtersApplied, setFiltersApplied] = useState(["All"]);
const filterListItemElements = filterData.map((el, index) => (
<button
className={`text-white ${filtersApplied.includes(el) ? '' : 'text-opacity-30 hover:text-opacity-70'} pl-0.5 text-xs block w-full cursor-pointer`}
key={index}
onClick={() => handleFilterClick(el)}
// eslint-disable-next-line react/no-unknown-property
aria-pressed={filtersApplied.includes(el)}
>
{el}
</button>
));
function handleFilterClick(val) {
if (!filtersApplied.includes(val)) {
// if item not already in the array
if (val === "All") {
// delete contents of Array and replace with "All"
setFiltersApplied(["All"]);
} else {
// first remove "All" from Array if currently in there
setFiltersApplied(
filtersApplied.filter(name => name !== "All")
);
// now add the new item
setFiltersApplied((filtersApplied) => [...filtersApplied, val]);
}
} else {
// item already in Array so remove
if(val === "All") return
let tempArray = [...filtersApplied]
tempArray.filter(name => name !== val)
// now check if there are no longer any filters as will need to change Array back to "All"
if(tempArray.length === 0) tempArray = ["All"]
setFiltersApplied(tempArray);
}
}
2
Answers
tempArray.filter(name => name !== val)
does not mutate the array – it returns a filtered array. So what you probably want isconst filteredArray = tempArray.filter(name => name !== val)
and then continue the check onfilteredArray
In your
handleFilterClick
function, you’re doing a good job of avoiding direct mutation of thefiltersApplied
array. However, there is a small mistake in your code that might lead to unexpected behavior.In the else block, you’re creating a copy of
filtersApplied
and filtering out the value that needs to be removed. However, you’re not updating the state with the new array. Instead, you’re updating the state with the originalfiltersApplied
array. This is because thefilter
method does not mutate the original array, but returns a new array. You need to capture this new array and update the state with it.I modify the part code to this;
As you see,
tempArray
is updated with the new array returned by thefilter
method. Then, the state is updated with this new array. This ensures that the state is always updated with a new array, avoiding direct mutation of the stater.