How to only dispatch FileList from dataTransfer after File items are loaded

ぃ、小莉子 提交于 2019-12-01 23:21:49

For those of you who are having this issue, for me I think the issue was that the Files in the Filelist weren't "plain ol' JavaScript objects" like I thought they were but in fact Files/Blobs.

I'm not sure of the details -- and would love it if someone would explain them -- but What I Think I Know is that the blob doesn't have keys like a standard JS object does so you can't just push it to the Redux store and see they key-value pairs of the properties I was expecting (lastModified, lastModifiedDate, name, path, preview, size, type, webkitRelativePath).

If you just looked at the blob, they only property was the preview because that was a property specifically set on the File/Blob by React Dropzone. To see the other properties, you have to call each one on the blob.

This is a simplified version of my solution below. I take in the Filelist array, create a new object to set the key-values on and iterate through each key and set it with its property on the newFile object. Finally I return that object. You can then set that object in your store and it will have the necessary data to work with the files.

onDrop(files) {
    const fileBlob = files[0];
    const newFile = {};
    _fileProperties.forEach(key => {
      newFile[key] = fileBlob[key];
    });

   return newFile;
}

const _fileProperties = [
  'lastModified',
  'lastModifiedDate',
  'name',
  'path',
  'preview',
  'size',
  'type',
  'webkitRelativePath'
];

There are probably lots of better ways of doing this and I'm sure my understanding is off so I'd still love it if someone would explain this better. In the meantime, this solution worked for me.

There are also some other places for more info such as MDN's File drag and drop article.

I had the same issue. I tried solutions provided by @Mitch Conquer and comment made by @Ishmael Smyrnow, but it returns the plain object instead of a File object. Also as discussed here , it's not recommended to store non-serializable objects in store. Therefore, what I did was, first converted file to base64 and store by just using FileReader.

const reader = new FileReader();
reader.readAsDataURL(file);

And then after converted back into file as solution provided by here.

export const dataURLtoFile = (dataurl, filename) => {
    var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while(n--){
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, {type:mime});
}

I tweaked the onDrop attribute as follows: onDrop={this.onDrop}, and added the file properties into my method - this worked for me.

I think the reason the above didn't quite work is because I have other input elements on in my component - the file upload is just part of a set I'm capturing.

Hope this helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!