Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React component does not rerender after useEffect (dependency array used)

I have an object state priceRanges in component A , which i initialize with a key and a value:

const [priceRanges, setPriceRanges] = useState({
        [randomId]: {
            "price": 0,
            "quantity": 0
        }
    })

And then pass it through props to component B:

<ComponentB pricesRanges={pricesRanges} ...props />

The problem is that in Component B , I am converting this object into an array on useEffect:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

React.useEffect(() => {
        const getArrayData = () => {
            const keys = Object.keys(priceRanges)
            keys.map(key => {
                console.log(priceRanges[key]["price"])
                priceRangesArray.push({
                    id: key,
                    price: priceRanges[key]["price"] ? priceRanges[key]["price"] : 0,
                    quantity: priceRanges[key]["quantity"] ? priceRanges[key]["quantity"] : 0
                })
            })
        }
        getArrayData()
    }, [priceRanges])

But the component does not rerender after the useEffect has run. As such, the component does not render the initial state that pricesRanges was initialized with. To test this, I did this:

{priceRangesArray.length > 0 ? 
            (priceRangesArray.map(quantityAndPrice => {
                return (
                    <div className="flex" key={quantityAndPrice.id}>
                        {console.log("I AM RENDERING")}
                        <input
                            ...props
                        />
                        <input
                            ...props
                        />
                    </div>
                )
            })) :<p>Hello</p>}

Which always renders Hello on mount . How can I tackle this ? Thanks you !

>Solution :

The only way to cause a rerender is to set state. Mutating an array during a useEffect will not cause a rerender. So you could fix this by adding a state variable, and then setting state once you’ve calculated the array.

However, i think that’s not the right approach here. Your array is derived data: it’s directly based on what’s in priceRanges, and you don’t want it to ever deviate from that. So for this, i would calculate the value in line during rendering the component:

const Example = ({ priceRanges }) => {
  const keys = Object.keys(priceRanges);
  const priceRangesArray = keys.map((key) => {
    return {
      id: key,
      price: priceRanges[key]["price"] ? priceRanges[key]["price"] : 0,
      quantity: priceRanges[key]["quantity"] ? priceRanges[key]["quantity"] : 0,
    };
  });

  // ...rest of the component
}

If performance is a concern, you can wrap this in useMemo to skip the calculation if priceRanges has not changed.

const Example = ({ priceRanges }) => {
  const priceRangesArray = useMemo(() => {
    const keys = Object.keys(priceRanges);
    return keys.map((key) => {
      return {
        id: key,
        price: priceRanges[key]["price"] ? priceRanges[key]["price"] : 0,
        quantity: priceRanges[key]["quantity"] ? priceRanges[key]["quantity"] : 0,
      };
    });
  }, [priceRanges]);

  // ... rest of the component
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading