1

I am trying to update the state with an array. But I need to keep the existing information in the array and just push more information into it.

Here is my state:

  const [filteredProducts, setFilteredProducts] = useState([]);

This is my function I am calling for the onClick event listener

const filteredByCategory = (event, category, products) => {
  const element = document.getElementById(event.target.id);
  
  if (element.checked) {
    const productsToAdd = products.filter(
      (product) => product.category === category
    );
    
    setFilteredProducts((currentFilteredProducts) => [
      ...currentFilteredProducts,
      ...productsToAdd,
    ]);
    
    dispatch({
      type: "PRODUCTS_FILTERED",
      payload: filteredProducts,
    });
  } else {
    let removedCheckedProducts = filteredProducts.filter((product) => {
      return product.category !== category;
    });
    
    setFilteredProducts(removedCheckedProducts);
    
    if (removedCheckedProducts.length >= 1) {
      dispatch({
        type: "PRODUCTS_FILTERED",
        payload: removedCheckedProducts,
      });
    } else {
      dispatch({
        type: "PRODUCTS_FILTERED",
        payload: allProducts,
      });
    }
  }
};
Carlotta
  • 334
  • 1
  • 13
Tim Taylor
  • 81
  • 1
  • 7
  • Does this answer your question? [Push method in React Hooks (useState)?](https://stackoverflow.com/questions/54676966/push-method-in-react-hooks-usestate) – Carlotta Aug 20 '21 at 08:36

2 Answers2

2

My assumption is that you expect the filteredProducts state value to reflect your changes right after setFilteredProducts:

setFilteredProducts((currentFilteredProducts) => [
    ...currentFilteredProducts,
    ...productsToAdd,
]);
dispatch({
    type: "PRODUCTS_FILTERED",
    payload: filteredProducts,
});

Unfortunately, that's not how state updates work. The set* function simply queues the update for the next render, but does not immediately update the state.

You could maintain a local variable to pass the update both into the local state and into the Redux store:

const updatedProducts = [
    ...filteredProducts,
    ...productsToAdd,
];
setFilteredProducts(updatedProducts);
dispatch({
    type: "PRODUCTS_FILTERED",
    payload: updatedProducts,
});
digitalbreed
  • 3,953
  • 4
  • 26
  • 24
0

digitalbreed identified the race condition correctly in his answer. An example of this behavior can be seen in this code sandbox by viewing the console after clicking the addProduct button

Thomas Burke
  • 1,105
  • 9
  • 20