1

I'm trying to set images after uploading them to cloud, but seems like i'm missing something . The output is not as desired .

I expect the output to be having all images. But it is just 0 instead.

 useEffect(() => {
    console.log("============ From UseEffect ==========")
    console.log("Images now Contain : ", images);
  }, [images]);

const uploadFilesToCloud = async () => {
    const data = new FormData();
    for (let i = 0; i < imageUrls.length; i++) {
      const finalImage = await getBase64FromUrl(imageUrls[i]);
      data.append("file", finalImage);
      data.append("upload_preset", "myPreset");
      const res = await fetch(
        "https://api.cloudinary.com/v1_1/dpurb6xes/image/upload",
        {
          method: "Post",
          body: data,
        }
      );
      const response = await res.json();
      setImages((old) => [...old, response.secure_url]);
    }
  };

const onClick = async (e) => {
await uploadFilesToCloud();
const myForm = {
  name: name,
  imageUrls: images,
};
  console.log("form data is ", myForm);
}

Suprisingly the output is :

enter image description here

My actual question is now .

  1. Though the images has one element before setting myForm.imgUrls = images. Even then myForm.imageUrls is having no element. How ?
  2. And what i want is , after both the received images are set only then the form should be initialized with images.

Can you please say how to do just that.

krishnaacharyaa
  • 14,953
  • 4
  • 49
  • 88
  • React state updates are asynchronously processed, but this doesn't mean the process is `async` or involves Promises, you just can't wait for React state to update. Is there a need for any state here? Can this `upload` function just return the array of images that `onClick` needs? – Drew Reese Apr 14 '22 at 08:02
  • But the upload function should be async because it involes images uploading to the cloud and getting responses from them, the reponses i want to actually store in the images array by setImages , but i am facing, the images are not updated as it was expected – krishnaacharyaa Apr 14 '22 at 08:06
  • How can i make sure that all the images are set and only then the form.formimages is initialized with images ? – krishnaacharyaa Apr 14 '22 at 08:07
  • Why is `upload` declared `async`? It is running completely synchronous code. What are you really trying to do with these images? Can you share a more accurate code example for what you are trying to accomplish? – Drew Reese Apr 14 '22 at 08:07
  • Hope the updated question now helps – krishnaacharyaa Apr 14 '22 at 08:12

1 Answers1

1

I don't think there's actually a need for state here. Map the imageUrls array to an array of fetch Promises and return Promise.all from upload. The onClick handler can await the array of Promises to resolve and use the array of resolved image URLs.

Example:

const App = () => {
  const upload = () => {
    const imgURLs = imageUrls.map(data => {
      return fetch(
        "https://api.cloudinary.com/v1_1/dpurb6xes/image/upload",
        {
          method: "Post",
          body: data,
        }
      ).then(response => response.json())
      .then(response => response.secure_url);
    });

    return Promise.all(imgURLs);
  };

  const onClick = async () => {
    const imageURLs = await upload();
    const myForm = {
      formImages: imageURLs,
    };
    console.log("Form details", myForm);
  };

  return (
    <>
      <div className="container">
        <button
          type="button"
          onClick={onClick}
        >
          Click me
        </button>
      </div>
    </>
  );
};

If you needed to store the image URLs in state the place to do that is in the onClick handler once everything resolves.

Example:

const onClick = async () => {
  const imageURLs = await upload();
  const myForm = {
    formImages: imageURLs,
  };
  console.log("Form details", myForm);
  setimages(imageURLs);
};
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • Thank you drew, but actually the thing is , imageUrls is array of different image urls, that i am actually changing to base64 and then storing in cloud , which is r meturning me the uploaded url after uploading succesfully , so i want to actually store the uploaded url in images using setimages. But i dont think , that is happening here, please correct me if i am wrong. – krishnaacharyaa Apr 14 '22 at 08:29
  • @KrishnaAcharya It's the last part of my answer, saving the images to local state *after* they've been fetched and returned to the handler. – Drew Reese Apr 14 '22 at 08:30
  • Thank you @Drew Reese for responses. But now i just added the real part of my code and the corresponding output . Can you please help me out with that. Sorry for actually making this question long and kinda confusing. But the output image and my last two points is my only question of concern – krishnaacharyaa Apr 14 '22 at 08:53
  • @KrishnaAcharya You seem to still not quite understand how Javascript closures and React state updates work. React state is const and closed over in callbacks. It won't ever update to a different value inside `onClick`. That's why my answer handles all the asynchronous logic in the "uploadFiles" function and returns the entire array of images that the `onClick` function is expecting. This is when you can take all the images and enqueue a single state update, if you even need the state at this point, IDK, it's not clear what the code does with any of what it fetched/uploaded. – Drew Reese Apr 14 '22 at 09:05