skip to Main Content
const cats = [
    1, 2, 3
  ];
  let arr = [];
  const [images, setImages] = useState([]);

  const generateCat = () => {
    fetch(
      "https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200"
    )
    .then(response=>{return response.json()})
    .then(data=>{
      let finalResult = data[0]['url']
      arr.push(finalResult)
      console.log(arr)
      return finalResult
    })
  };

  for(let i=0;i<cats.length;i++){
    generateCat()
    setImages(arr)
    console.log('Images: '+images)
  }

My problem is that I’m encountering an issue with setState() causing an infinite loop in my React component. Specifically, I’m making an API call to retrieve an image of a cat and pushing the image URL to an array called arr. Then, I’m attempting to update the state of the component by calling setImages(arr) and logging the images variable to the console.

However, calling setImages() triggers a re-render of the component, which causes the for loop to execute again, leading to another API call, another push to arr, and another call to setImages(), resulting in an infinite loop.

I am expecting the state variable images to have 3 img urls since the for loop is being iterated thrice.

2

Answers


  1. I am assuming this code is inside of a react component so here is modified example that should prevent the pre-rendering:

    
    const cats = [
        1, 2, 3
      ];
    
    const ExampleComponent = () => {
    
    
      const [images, setImages] = useState([]);
      
      // this code will only be called on initial load of the component
      useEffect(() => {
        const generateCat = () => {
        fetch(
          "https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200"
        )
        .then(response=>{return response.json()})
        .then(data=>{
          let finalResult = data[0]['url']
          
          setImages(prev => [...prev, finalResult])
        })
      };
    
      for(let i=0;i<cats.length;i++){
        generateCat()
      }
      },[])
    
        console.log('Images: '+images)
    
      return <div>The Rest of your component here</div>
      
    }
    
    
    Login or Signup to reply.
  2. You need to wrap your fetch operations in a useEffect:

    import { useState, useEffect } from "react";
    
    const API_URL =
      "https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200";
    
    async function getCat() {
      const response = await fetch(API_URL);
      const data = await response.json();
      return data[0].url;
    }
    
    export default function App() {
      const [pics, setPics] = useState([]);
      useEffect(() => {
        Promise.all(Array.from({ length: 3 }, getCat)).then(setPics);
      }, []);
    
      if (!pics.length) {
        return "Loading...";
      }
    
      return (
        <div className="app">
          {pics.map((url) => (
            <img key={url} src={url} alt="A kitten" />
          ))}
        </div>
      );
    }
    
    .app {
      display: flex;
      flex-direction: column;
    }
    <script type="text/babel">
    const { useState, useEffect } = React;
    
    const API_URL =
      "https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200";
    
    async function getCat() {
      const response = await fetch(API_URL);
      const data = await response.json();
      return data[0].url;
    }
    
    function App() {
      const [pics, setPics] = useState([]);
      useEffect(() => {
        Promise.all(Array.from({ length: 3 }, getCat)).then(setPics);
      }, []);
    
      if (!pics.length) {
        return "Loading...";
      }
    
      return (
        <div className="app">
          {pics.map((url) => (
            <img key={url} src={url} alt="A kitten" />
          ))}
        </div>
      );
    }
    
    ReactDOM.createRoot(document.querySelector("#root")).render(<App />);
    </script>
    
    <div id="root"></div>
    <script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search