Tim Taylor
Tim Taylor

Reputation: 81

How to append to state array in React hooks?

I have a state set as

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

I want to be able to append to the end of that state. I am currently trying

products.forEach((product) => {
        if (product.category === category) {
          setFilteredProducts([...filteredProducts, product]);
        }
      });

It it looping through the products array correctly. I can even log the product after the setFilteredProducts and it logs the correct ones I want. I am calling this with an onClick.

Upvotes: 3

Views: 11485

Answers (5)

bebewr
bebewr

Reputation: 126

The problem is, that setFilteredProducts doesn't immediately affect products. It's React's job to decide when to update the state. So when you loop over products, you'll probably ending up adding just the last item, because filteredProducts wasn't updated yet. What you can do, is preparing an array of products to add:

const productsToAdd = products.filter(product => product.category === category);

And then append them:

setFilteredProducts([...products, ...productsToAdd]);

Upvotes: 0

Curt Bryan III
Curt Bryan III

Reputation: 46

I think you want what the ES6 built-in function does. You can rewrite your code to give you the the products that match the category like this:

const filteringTheProducts = products.filter(product => {
    return product.category === category
})

setFilteredProducts(filteringTheProducts)

The result of the filtering will be the array of all the products that match that criteria.

Here is the documentation for .filter() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

Upvotes: 0

digitalbreed
digitalbreed

Reputation: 4070

You would only append the last match to the existing filteredProducts array.

You can add all matches like so:

setFilteredProducts([...filteredProducts, ...products.filter((product) => product.category === category)]);

Upvotes: 1

Ctznkane525
Ctznkane525

Reputation: 7465

I'd recommend you do this in 2 steps:

Create an array of the new products you plan to add

let productsToAdd = [];

products.forEach((product) => {
    if (product.category === category) {
      productsToAdd.push(product);
    }
  });

Then combine the arrays and set state

setFilteredProducts([...filteredProducts, ...productsToAdd]);

Upvotes: 0

Federkun
Federkun

Reputation: 36989

Find all the products you want to add:

const productsToAdd = products.filter(product => product.category === category)

Then append them

setFilteredProducts((currentFilteredProducts) => ([...currentFilteredProducts, ...productsToAdd]));

The issue with your example is that filteredProducts may get stale after the first iteration. setFilteredProducts will not run synchronously, and filteredProducts keep the original value, until the re-render happen.

Upvotes: 5

Related Questions