skip to Main Content

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


  1. tempArray.filter(name => name !== val) does not mutate the array – it returns a filtered array. So what you probably want is const filteredArray = tempArray.filter(name => name !== val) and then continue the check on filteredArray

    Login or Signup to reply.
  2. In your handleFilterClick function, you’re doing a good job of avoiding direct mutation of the filtersApplied 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 original filtersApplied array. This is because the filter 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;

    let tempArray = [...filtersApplied]
    tempArray = 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);
    

    As you see, tempArray is updated with the new array returned by the filter 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search