2

Can you please explain why the following results in an infinite loop with the following error:

Uncaught Invariant Violation: Too many re-renders. React limits the number of renders to prevent an infinite loop.

import React from "react";
import { useState } from 'react';

function MyImageComponent(props) {
  const {
    images
  } = props;

  const [windowWidth, updateWindowDimensions] = useState(window.innerWidth);

  window.addEventListener('resize', updateWindowDimensions(window.innerWidth)); //error here


  return (
    <div>
    {windowWidth}
    </div>
  );

}

export default MyImageComponent;

I believe I can solve using the useEffect API but I don't understand conceptually what the problem is... it appears the render is being called multiple times because state is being set in a loop... but given the update function updateWindowDimensions is binded to an event listener which is not running infinitely I don't understand it.

To note: the error appears with or without a window resize.

2
  • 1
    window.addEventListener('resize', () => updateWindowDimensions(window.innerWidth)) Commented Sep 17, 2019 at 0:19
  • @AlexanderStaroselsky omg 🤣🤣 I see, thank you! Commented Sep 17, 2019 at 0:29

2 Answers 2

2

Currently you are not handling the resize event handler correctly. The first argument of the resize event handler would be a resize event. Also you would pass a function to a handler rather than executing a function as a handler. Try the following instead:

window.addEventListener('resize', () => updateWindowDimensions(window.innerWidth))

Hopefully that helps!

Sign up to request clarification or add additional context in comments.

Comments

2

@Alexander Staroselsky answer will solve your exact issue, but on each render window.addEventListener will be called and new event handler will be assigned to 'resize' event. So you'll quickly end up with hundreds of the same event listeners calling updateWindowDimensions(window.innerWidth) (You may see it by adding console.log(window.innerWidth) to callback).

I suggest to use useEffect with empty dependency list. So it will be called exactly once and bind one event listener to resize event.

useEffect(() => {
    window.addEventListener('resize', () => {
        updateWindowDimensions(window.innerWidth)
  })}, []);

2 Comments

This is a great answer and important point. I’d take it one step further and add example of clean up (removing event listener) from the hook.
Thank you for your clarification on the need for lifecycle methods.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.