skip to Main Content

I have a problem with infinite loop in my code. I am trying set icons to my weather forecast list. But I am getting "Too many re-renders. React limits the number of renders to prevent an infinite loop." error.

There is important information: I can’t using this method with useEffect. It cause any error about my loading screen.

I have imported these icons:

import ThunderIcon from '../Images/ThunderIcon.svg'
import SunnyIcon from '../Images/SunnyIcon.svg'
import SunnyCloud from '../Images/SunnyCloud.svg'
import SunnyRainIcon from '../Images/SunnyRainIcon.png'
import RainyIcon from '../Images/RainyIcon.svg'

There is my selectIcon function. I am setting icons with switch-case:

const selectIcon = (type) => {
    switch (type) {
      case "sunny":
        setWeatherIcon(SunnyIcon);
        break;
      
      case "rainy":
        setWeatherIcon(RainyIcon);
        break;

      case "sunny rainy":
        setWeatherIcon(SunnyRainIcon);
        break;

      case "thunder":
        setWeatherIcon(ThunderIcon);
        break;

      case "sunny cloudy":
        setWeatherIcon(SunnyCloud);
        break;
    }
  }

And I am trying implement this on JSX. I think reason of problem in here. But I can’t solve this problem. Here is my component:

return (
    <div className="WeeklyForecast">
      <div className="Prev-Btn">
        <button onClick={prevClick}>&lt;</button>
      </div>
      <div className="Forecast-List">

        {days.map((day) => (
          <div key={day}>
            <p>{day}</p>
            {selectIcon(selectedWeekData[day].type)}
            <img src={weatherIcon} alt="" />
            <p>{selectedWeekData[day].degree}°</p>
          </div>
        ))}
      </div>
      <div className="Next-Btn">
        <button onClick={nextClick}>&gt;</button>
      </div>
    </div>
  );

I am trying set icons to my weather forecast list. But I am getting "Too many re-renders. React limits the number of renders to prevent an infinite loop." error.

3

Answers


  1. You can modify your selectIcon function to return the selected icon rather than directly updating the state inside the function. Then, you can call this function inside the JSX without causing a re-render.

    const selectIcon = (type) => {
      switch (type) {
        case "sunny":
          return SunnyIcon;
        case "rainy":
          return RainyIcon;
        case "sunny rainy":
          return SunnyRainIcon;
        case "thunder":
          return ThunderIcon;
        case "sunny cloudy":
          return SunnyCloud;
        default:
          return null; // or a default icon
      }
    }
    
    return (
      <div className="WeeklyForecast">
        <div className="Prev-Btn">
          <button onClick={prevClick}>&lt;</button>
        </div>
        <div className="Forecast-List">
          {days.map((day) => (
            <div key={day}>
              <p>{day}</p>
              {selectIcon(selectedWeekData[day].type) && (
                <img src={selectIcon(selectedWeekData[day].type)} alt="" />
              )}
              <p>{selectedWeekData[day].degree}°</p>
            </div>
          ))}
        </div>
        <div className="Next-Btn">
          <button onClick={nextClick}>&gt;</button>
        </div>
      </div>
    );
    
    Login or Signup to reply.
  2. The first thing that I’d suggest is that the switch-case (repetition of setWeatherIcon) function might be the cause of the problem.

    My suggestion: Please extract it outside of component and see if the issue still remains.

    Login or Signup to reply.
  3. On every render you do this:

    selectIcon(selectedWeekData[day].type)
    

    Which calls a function that updates state:

    setWeatherIcon(SunnyIcon);
    

    State updates trigger a re-render, which re-invokes the above code, which triggers a re-render, which re-invokes the above code, etc., etc. (You’re also updating that one state value for every element in an array, which doesn’t make much sense as only the last update would take effect anyway.)

    Don’t update state on every render.

    Why do you even need to use state for this anyway? It looks like you just want to select an icon based on a value. So just return that icon:

    const selectIcon = (type) => {
      switch (type) {
        case "sunny":
          return SunnyIcon;
        case "rainy":
          return RainyIcon;
        case "sunny rainy":
          return SunnyRainIcon;
        case "thunder":
          return ThunderIcon;
        case "sunny cloudy":
          return SunnyCloud;
      }
    }
    

    And call that function inline:

    <div key={day}>
      <p>{day}</p>
      <img src={selectIcon(selectedWeekData[day].type)} alt="" />
      <p>{selectedWeekData[day].degree}°</p>
    </div>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search