2
import React, { useState } from "react";

export default function App() {
  const [photo, setPhoto] = useState([]);
  const pictures = listObjects();  // getting image flies from AWS.S3, and they are array of objects, and the key "Key" contains image files like "dog.gif"
  const getAllPictures = (pics) => {
    pics.then((data) => {
      return data.forEach((picture) => {
        // console.log(picture.Key); I've got a stirng img file
        setPhoto((photo) => [...photo, picture.Key]);
      });
    });
  };
  getAllPictures(pictures);

Hi. I'm trying to put a list of image files, like "dog.gif", into react state using hooks, and I used a wrapper function. Now I don't see any error on my local server, but after a couple of seconds later, my laptop fan spins and never stops until I close the browser, also occasionally I can see the spinning beach ball on my laptop. I'm guessing I'm either doing wrong to put the list into the state, or I'm getting too much data from AWS.S3. Can anyone point me out what am I doing wrong here, please?

  • How many objects are in the list ? Also on large arrays, using forEach is slower than using a for loop (as for each instanciate a new function on each iteration). When you inspect your network tab in your developer tools, do you see your calls resolving well? – Ben Apr 30 '20 at 23:49
  • Now I can see 157 image files (string) on my console. –  Apr 30 '20 at 23:52

2 Answers2

3

You may want to set the state once, otherwise it will run into an infinite re-render loop.
You could initialize some data on component mount with useEffect hook.

Here is an example using useEffect:

import React, { useState, useEffect } from "react";

export default function App() {
  const [photo, setPhoto] = useState([]);

  const getAllPictures = (pics) => {
    pics.then((data) => {
      return data.forEach((picture) => {
        // console.log(picture.Key); I've got a stirng img file
        setPhoto((photo) => [...photo, picture.Key]);
      });
    });
  };

  useEffect(() => {
    const pictures = listObjects();
    getAllPictures(pictures);
  }, [])

What is wrong with the current implementation:

export default function App() {
  // photo has an initial value
  const [photo, setPhoto] = useState([]);
  const pictures = listObjects();


  const getAllPictures = (pics) => {
    pics.then((data) => {
      return data.forEach((picture) => {
        // The setState will trigger a re-render
        setPhoto((photo) => [...photo, picture.Key]);
      });
    });
  };

  // On each setState (re-render) this function will be executed
  getAllPictures(pictures);
Simon Bruneaud
  • 2,263
  • 2
  • 12
  • 24
2

@Yuya, the question has to do with fetching and setting data using a react functional component. the useEffect hook is a good candidate for an api request that causes a side effect (re-render) by setting the state. what Simon wrote is correct, except the hook also needs to be imported as well from the top, like this

import React, { useState, useEffect } from "react";

in addition, the getAllPictures api call looks a bit off.

pics.then((data) => {
   return data.forEach((picture) => {
   // The setState will trigger a re-render
     setPhoto((photo) => [...photo, picture.Key]);
   });
});

pics is an object, NOT a promise. doing pic.then would yield a type error. for more details about .then usage, take a look at this stackoverflow answer. I'm guessing the call should look something like this:

getAllPictures('http://url/to/the/endpoint').then((data) => {...})
user3366943
  • 253
  • 1
  • 6