2

I want to add picture files with Dropzone and show preview on browser. So, I have to get src which can use at <img />. So I do this process:

  const handleAddImages = async (inputImages: any[]): Promise<void> => {
    const imagesWithSrc = inputImages.map((img) => {
      const reader = new FileReader();
      new Promise((resolve, reject) => {
        reader.onloadend = () => resolve(reader.result);
        reader.onerror = reject;
        reader.readAsDataURL(img);
      }).then(() => (img.src = reader.result));
      return img;
    });

    const nextImages = [...currentImages, ...imagesWithSrc];
    handleOnChange({
     //set state
      target: {
        name: "images",
        value: nextImages,
      },
    });
  };

And show the images in this component:

export const FileList = ({
  images
}: any) => {
  const imgs: any[] = images;

  return (
      <Wrapper>
        {imgs.map((img, index) => (
            <ImgBox key={index}>
              <img src={img.src} />
            </ImgBox>
        ))}
      </Wrapper>
  );
};

I have an images array imgs and contains image file objects. When I do this:

console.log(imgs[0]);

it will output every attributes in image file object of index 0 including the image source src in base64 from filereader API.

but when I do this:

console.log(imgs[0].src);

it will output undefined,

even I do console.log in map like this:

imgs.map((img, index) => {
  console.log(img);
  console.log(img.src);
})

and get the same result, what is the problem?

console.log("imgs[0]", imgs[0]); 
console.log("imgs[0].src", imgs[0].src);

ouput:

enter image description here

By the way, I can get the size attribute by imgs[0].size at first, and get the imgs[0].src after add another picture.

Bill
  • 21
  • 3

2 Answers2

0

As defined in the W3C File API, the File interface (which extends Blob) does NOT have an src property. While your environment may display an src property, it appears to be inaccessable from your code, and may be added by your browser's runtime or another part of your code in a way that makes it inaccessable. Honestly, without more information, I cannot say for sure where the src property is coming from.

If you want to base64-ify your File object, try using the FileReader API:

let blob = imgs[0];

let reader = new FileReader();
reader.readAsDataURL(blob);

reader.onload = function() {
  console.log(reader.result); //-> "data:image/png;base64,iVBORw..."
};
luawtf
  • 576
  • 8
  • 21
  • Thanks for your answer. I add the part of adding `src` property. maybe it help for finding the reason I can access the `src`. – Bill Jul 12 '21 at 04:58
  • Oh, you've got a whole other problem here. You're not awaiting the Promise inside the lambda passed to `inputImages.map`. The `src` property wont be updated until after all your code has been executed and the React render is complete. – luawtf Jul 12 '21 at 05:01
  • 1
    but why I can see the `src` in the output by `console.log(imgs[0])` but undefined by `console.log(imgs[0].src)`?? – Bill Jul 12 '21 at 05:42
  • Hmm, good point, I think the path to a solution would involve you restructuring your code to wait for the encoding to complete (which I'm almost certain is your problem) and also not modifying an object that is part of an API that you don't manage in your own code (that's just good practice, and will make your code easier to maintain and reason about. Consider returning an object like { file, src }, and make sure to use await to wait for the encoding to complete. – luawtf Jul 12 '21 at 06:00
  • yeah, I thought that restructuring is a good idea, too. Anyway thanks for your help and suggestion, and I will try to solve it in another way to process file. – Bill Jul 12 '21 at 06:11
0

It seems to be problem with filereader API and I solved my problem with this answer. https://stackoverflow.com/a/34495914/16426251

Bill
  • 21
  • 3