Reputation: 1674
I have a component with an array of objects, which among other things i am filtering based on a string. Problem is when I try to set the return of this filter to the local state, it's throwing errors that i am not quite understanding the reason.
import React, { useState, useEffect } from 'react';
import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag'
const ProductsGrid = () => {
const [productsList, setProductsList] = useState([]);
const { loading, data } = useQuery(GET_PRODUCTS);
if (loading) return <div><h4>bla bla bla</h4></div>
const { merchants } = data;
let filtered = [];
merchants.map(merchant => {
merchant.products.map(product => {
if (product.name.includes('Polo')) {
filtered.push(product);
}
})
})
console.log({ filtered });
}
This is printing the following:
So, because I want this array in my state, I decided to do this: setProductsList(filtered);
and what happened after inserting this line was this:
It started rendering multiple times. I assumed that, every time the state changes, it re-renders the component (correct me if im wrong). I don't know why it did it multiple times though.
So, I thought on using useEffect to achieve the expected behaviour here.
useEffect(() => {
console.log('useeffect', data);
if (data) {
const { merchants } = data;
console.log({merchants })
let filtered = [];
merchants.map(merchant => {
merchant.products.map(product => {
if (product.name.includes('Polo')) {
filtered.push(product);
// console.log({ filtered });
}
})
})
console.log({ filtered });
setProductsList(filtered);
}
}, [data])
So, I am understanding what's going on here and what is this last error about.
I assume my approaching is towards the right direction, using useEffect
to run the function only once.
Upvotes: 1
Views: 6553
Reputation: 2775
Your problem is due to the useEffect
call occurring after the if (loading)
condition, which returns early.
Calling hooks after a conditional return statement is illegal as it violates the guarantee that hooks are always called in exactly the same order on every render.
const { loading, data } = useQuery(GET_PRODUCTS);
const [productsList, setProductsList] = useState([]);
if (loading)
return (
<div>
<h4>bla bla bla</h4>
</div>
); // <-- Cannot use hooks after this point
useEffect(/* ... */)
To fix, move the useEffect
call to be before the conditional.
Upvotes: 5