Sku
Sku

Reputation: 183

Trying to reset a list before filtering, but having trouble with the asynchronous states

So i have a const with an array of objects, named "data", a state that receive that data so I can update the screen when I change it, and I have a function that filter that data.

Every time that the user change the state of an HTML select, I trigger a function named handleChange that calls the filter function, so the user user can see the filtered content. The problem is that I want to reset the state that receives the data, with the original data before filtering it, so if the user change one of the selects, it filter based on the original data, not the previous changed one, but when I try to update the state with the const data value, it doesn't work.

Here is my code

  const [list, setList] = useState<IData[]>([...data]);
  const [filter, setFilter] = useState<IFilter>({
    name: "",
    color: "",
    date: "",
  });

  function handleChange(
    key: keyof IData,
    event: React.ChangeEvent<{ value: string }>
  ): void {
    const newFilter = { ...filter };
    newFilter[key as keyof IData] = event.target.value;
    setList([...data]); // reset the data
    setFilter({ ...newFilter }); // set the filter value
    filterList();
  }



  function filterList(): void {
    const keys = Object.keys(filter) as Array<keyof IData>;

    keys.forEach((key: keyof IData) => {
      if (filter[key]) {
        const newList = list.filter((item: IData) => item[key] === filter[key]);
        setList([...newList]);
      }
    });
  }

the problem is here

    setList([...data]); // reset the data
    setFilter({ ...newFilter }); // set the filter value
    filterList();

apparently, when the filterList happens, the list state is not yet restarted with the data value, since if I console log it inside filterList(), it return me only the list that was previous filtered. Is there a way for me to make sure that the setList happens before filtering, so I'm sure that the list that is filtered is always based on the initial value?

Upvotes: 1

Views: 114

Answers (1)

Nadia Chibrikova
Nadia Chibrikova

Reputation: 5036

You can access the updated values inside useEffect (more about useEffect), so instead of calling filterList() directly inside the handler you move it inside the hook:

React.useEffect(()=>{filterList();},[list,filter])

Alternatively, you can pass the values as parameters to the function, after you updated the state with them

filterList(newList, newFilter)

UPDATE As you update list inside filterList you'll need some sort of a flag to indicate if you need to filter of not (I'd use useRef). Note that it would be preferable to pass parameters into filterList instead, because this way there will be one less rendering cycle. Here is a simplified example of how both can work, let me know if they make sense : https://jsfiddle.net/6xoeqkr3/

Upvotes: 1

Related Questions