joshmcculloch09
joshmcculloch09

Reputation: 11

I've created an infinite loop trying to use a switch statement in react

I don't know how but the following code is getting an erro on the console saying "react-dom.development.js:16317 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."

Really puzzled as I don't know why this is happening. I am trying to create an image slider so I have a method that adds different images to a list based on a switch statement, then passes that list down to the child to be rendered.

import { useEffect, useState } from "react";
import BikeDisplayImages from "./BikeDisplayImages";
import BikeDisplayTable from "./BikeDisplayTable";
import fixie_frame from "../../images/fixie-frame.png";
import tour_frame from "../../images/tour-frame.png";
import road_disc from "../../images/road-disc-frame_2.png";
import gravel_disc from "../../images/gravel-disc-frame.png";
import tumbleweed from "../../gifs/tumbleweed.gif";
import flared_bars from "../../images/Flared_Bars.png";
import drop_bars from "../../images/Drop_Bars.png";
import bullhorn_bars from "../../images/Bullhorn_Bars.png";
import flat_bars from "../../images/Flat_Bars.png";

const BikeDisplayWorker = ({ changedBike, bike }) => {
  const [listOfImages, setListOfImages] = useState([]);
  useEffect(() => {
    if (changedBike) {
      chooseImages();
    }
  });
  function chooseImages() {
    let tempList;
    tempList.concat(chooseFrame(bike.frame.frameStyle));
    tempList.concat(chooseBars(bike.handleBarType));
    setListOfImages(tempList);
  }
  function chooseBars(barType) {
    switch (barType) {
      case "FLARE":
        console.log("Flare Bars");
        return <img src={flared_bars} alt="Flared Bars" />;
      case "DROPS":
        console.log("Drop Bars");
        return <img src={drop_bars} alt="Drop Bars" />;
      case "BULLHORNS":
        console.log("Bull Bars");
        return <img src={bullhorn_bars} alt="Bullhorn Bars" />;
      case "FLAT":
        console.log("Flat Bars");
        return <img src={flat_bars} alt="Flat Bars" />;
      case "NONE_SELECTED":
        console.log("No Bars");
        return <img src={tumbleweed} alt="No Bars Chosen" />;
      default:
        console.log("No Bars");
        return <img src={tumbleweed} alt="No Bars Chosen" />;
    }
  }
  function chooseFrame(frameStyle) {
    switch (frameStyle) {
      case "TOUR":
        console.log("Tour Frame");
        return <img src={tour_frame} alt="Touring frame" />;
      case "CITY":
        console.log("FIXIE!!");
        return <img src={fixie_frame} alt="Single-speed frame" />;
      case "ROAD":
        console.log("Road Disc Frame");
        return <img src={road_disc} alt="Road Frame, Disc Brakes" />;
      case "GRAVEL":
        console.log("Gravel Disc Frame");
        return <img src={gravel_disc} alt="Gravel Frame, Disc Brakes" />;
      case "NONE_SELECTED":
        console.log("No Frame");
        return <img src={tumbleweed} alt="No Frame Chosen" />;
      default:
        console.log("No Frame");
        return <img src={tumbleweed} alt="No Frame Chosen" />;
    }
  }

  return (
    <div>
      <BikeDisplayImages bike={bike} images={listOfImages}
      />
      <BikeDisplayTable bike={bike} />
    </div>
  );
};
export default BikeDisplayWorker;

I don't think this is the problem, but is concat the correct method call to add an item to a list in this way??

I have tried putting the useEffect is different locations to see if there is a better way of calling it. But I think the error is occuring before the method is run. This was working when I only needs to display a single image, but now that I have a slider and want multiple images, it has fallen over.

Upvotes: 0

Views: 213

Answers (2)

GeorgeFkd
GeorgeFkd

Reputation: 69

Your problem probably lies in the useEffect. useEffect takes another argument, the dependency array,without it, it runs on every render. That's why you have an infinite loop, your useEffect runs->sets the state which causes a rerender->the rerender will run again your useEffect and so on.

From the react docs(old):

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.

Also another potential source of problems is how you are using the concat method.

<script>
 function chooseImages() {
    let tempList;
    tempList.concat(["hello"]);
    tempList.concat(["world"]);
    console.log("Concatenating arrays",tempList);
  }
  function chooseImages2(){
    let tempList = "";
    tempList.concat("hello");
    tempList.concat("world");
    console.log("Concatenating strings",tempList)
  }
  //chooseImages();
  chooseImages2();
</script>

In the picture below i hope it is more clear, that the concat function returns something

Upvotes: 0

dbuchet
dbuchet

Reputation: 1651

Your problem comes from your useEffect with no dependency array, and which changes the state. So you're calling your useEffect, which change the state, which triggers a re-render, which calls your useEffect, which change the state,...

So add a dependency array to your useEffect :)

Upvotes: 1

Related Questions