Search code examples
reactjsreact-reduxreact-hooks

"Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."


Hi I have been stuck in a React Function useState. I just want to learn hooks and useState, but I can not have any progress even struggling too much to find a solution. Here is my full react function:

import React, { useState } from 'react';
import './MainPart.css';

function MainPart(props) {
  const [orderData_, setOrderData_] = useState(props.orderData);

  let topicData_ = props.topicData;
  let titleData_ = props.titleData;
  let infoData_ = props.infoData;

  return (
    <div className='MainPart'>
      <div className='mainWindow'>{getPics(orderData_)}</div>
      <div className='information'>
        <div className='moreNewsDivs'>
          <div className='moreNewsDiv1'>
            <h4>MORE NEWS</h4>
          </div>
          <div className='moreNewsDiv2'>
            <button
              className='previous-round'
              onClick={setOrderData_(previous(orderData_))}
            >
              &#8249;
            </button>
            &nbsp;&nbsp; &nbsp;&nbsp;
            <button href='/#' className='next-round'>
              &#8250;
            </button>
          </div>
        </div>
        <hr />
        <div className='topicDiv'>
          <h5 className='topicData'>{topicData_}</h5>
          <h5 className='titleData'>{titleData_}</h5>
          <h6 className='infoData'>{infoData_}</h6>
        </div>
      </div>
    </div>
  );
}

function previous(orderData_) {
  let newOrderData;

  if (orderData_ === 3) {
    newOrderData = 2;
    console.log(newOrderData);
    return newOrderData;
  } else if (orderData_ === 1) {
    newOrderData = 3;
    console.log(newOrderData);
    return newOrderData;
  } else {
    newOrderData = 1;
    console.log(newOrderData);
    return newOrderData;
  }
}

function next(orderData_) {
  let newOrderData;

  if (orderData_ === 3) {
    newOrderData = 1;
  } else if (orderData_ === 2) {
    newOrderData = 3;
  } else {
    newOrderData = 2;
  }
  return newOrderData;
}

const getPics = picOrder => {
  if (picOrder === 1) {
    return (
      <img
        src={require('../assets/desktopLarge/mainImage.png')}
        className='MainImage'
        alt=''
        id='mainImage'
      />
    );
  } else if (picOrder === 2) {
    return (
      <img
        src={require('../assets/desktopLarge/bridge.png')}
        className='MainImage'
        alt=''
        id='mainImage'
      />
    );
  } else {
    return (
      <img
        src={require('../assets/desktopLarge/forest.png')}
        className='MainImage'
        alt=''
        id='mainImage'
      />
    );
  }
};

export default MainPart;

I am getting an error while using useState. Even loading the page fresh and not pressed to anything my buttons onClick event listener activated and As I mentioned before at the topic My Error:

"Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."


Solution

  • The problem can be found in your onClick prop:

    <button className="previous-round" onClick={setOrderData_(previous(orderData_))}>&#8249;</button>
                                                ^
    

    Everything between the curly braces gets evaluated immediately. This causes the setOrderData_ function to be called in every render loop.

    By wrapping the function with an arrow function, the evaluated code will result in a function that can be called whenever the user clicks on the button.

    <button className="previous-round" onClick={() => setOrderData_(previous(orderData_))}
    >&#8249;</button>
    

    You can find more information about JSX and expressions in the official docs https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx

    Infinite re-render loop

    The reason for the infinite loop is because something (most likely setState) in the event callback is triggering a re-render. This will call the event callback again and causes React to eventually stop and throw the 'Too many re-renders.' error.

    Technical explanation

    To better understand the reason why JSX works this way see the code below. JSX syntax is compiled to plain JavaScript and every prop will be passed as a value in an Object. With this knowledge, you will see that the handleEvent() is being called immediately in the last example when rendering the component.

    // Simple example
    const Button = () => <button>click me</button>;
    const Button = () => createElement("button", null, "click me");
    
    // Correct callback prop
    const Button = () => <button onClick={handleClick}>click me</button>
    const Button = () => createElement('button', { onClick: handleClick }, "click me")
    
    // Wrong callback prop
    const Button = () => <button onClick={handleClick()}>click me</button>;
    const Button = () => createElement('button', { onClick: handleClick() }, "click me")