Home > Enterprise >  React: Infinite Loop with a onClick image that change should change another image src
React: Infinite Loop with a onClick image that change should change another image src

Time:12-08

I'm getting an infinite Loop in my React application.

I'm trying to get a previous Image and next Image button. In developement I handle this with an image tag. If my component is loading up the error accures.

Has somebody an idea how I can solve this issue?

Sorry for the spagetti-code I'm trying try and error and there I issued lots of useState's :D.

Thank you in advance!

Some explaining: the "imageArray" does contain an array with all picture names.

The "activeIndex" does contain the active index of the imageArray providing by another component.

The other two useStates should be self explaining :)

function FullImage(props) {
  const [imageArray, setImageArray] = [props.imageArray];
  const [activeIndex, setActiveIndex] = useState(props.activeIndex);
  const [imageLink, setImageLink] = useState("/uploads/1/"   active   "");
  const [newImageLink, setNewImageLink] = useState(null);

  setNewImageLink("/uploads/1/"   imageArray[activeIndex - 1]   "");

  return (
    <div className="activeImage">
      <img
        src="/img/websrc/prev.png"
        className="prevImage"
        onClick={() => setImageLink(newImageLink)}
      ></img>
      <img src={imageLink} className="mainImage"></img>
      <img src="/img/websrc/next.png" className="nextImage"></img>
    </div>
  );
} 

The error:

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

The above error occurred in the <FullImage> component:

CodePudding user response:

I fixed it with a lot of try and error. But for anyone who has the same problem i fixed it by getting a second array with the actual links. Also I was able to reduce my useState's and as well I added a keydown listener to navigate with arrow keys

function FullImage(props) {
  const [activeIndex, setActiveIndex] = useState(props.activeIndex);
  const [imageLink, setImageLink] = useState(
    "/uploads/"   props.pid   "/"   props.active   ""
  );

  const imageArrayWithLinks = [];

  for (let index = 0; index < props.imageArray.length; index  ) {
    imageArrayWithLinks.push(
      "/uploads/"   props.pid   "/"   props.imageArray[index]
    );
  }

  useEffect(() => {
    document.addEventListener("keydown", detectKeyDown, true);
  }, []);

  const detectKeyDown = (e) => {
    console.log(e.key);
    if (e.key === "ArrowLeft") {
      setImageLink(imageArrayWithLinks[activeIndex - 1]);
      setActiveIndex(activeIndex - 1);
    } else if (e.key === "ArrowRight") {
      setImageLink(imageArrayWithLinks[activeIndex   1]);
      setActiveIndex(activeIndex   1);
    }
  };

  return (
    <div className="activeImage">
      <img
        src="/img/websrc/prev.png"
        className="prevImage"
        onClick={() => {
          setImageLink(imageArrayWithLinks[activeIndex - 1]);
          setActiveIndex(activeIndex - 1);
        }}
      ></img>
      <img src={imageLink} className="mainImage"></img>
      <img
        src="/img/websrc/next.png"
        className="nextImage"
        onClick={() => {
          setImageLink(imageArrayWithLinks[activeIndex   1]);
          setActiveIndex(activeIndex   1);
        }}
      ></img>
    </div>
  );
}

Hope this will help some people.

CodePudding user response:

In React, you can use the onClick event to handle a click on an image and change the src attribute of another image. However, if you are not careful, you can accidentally create an infinite loop where the onClick event keeps firing and changing the src attribute, causing the event to fire again, and so on.

To avoid this, you can use a boolean flag to track whether the onClick event has already fired and stop it from firing again until the flag is reset. Here is an example of how to do this:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isClicked: false,
    };
  }

  handleClick() {
    if (!this.state.isClicked) {
      // Change the src attribute of another image
      // ...

      this.setState({ isClicked: true });
    }
  }

  render() {
    return (
      <div>
        <img src={image1Src} onClick={this.handleClick} />
        <img src={image2Src} />
      </div>
    );
  }
}

In this example, the handleClick method is called when the first image is clicked. It checks the isClicked flag in the component's state, and if it is not set, it changes the src attribute of the second image and sets the flag to true. This prevents the handleClick method from being called again until the flag is reset.

You can reset the flag by adding a button or some other UI element that allows the user to reset the state, or you can reset it automatically after a certain amount of time using setTimeout.

  • Related