Reputation: 1903
I want to create an image
uplaoder based on base64
and I want to get results as an array
but I got empty!
array, I know maybe it's a asynchronous
issue, but I don't know how to use async, await
in map
any idea?
const [array, setArray] = useState([]);
const fileBase64 = (img) => {
let result = [...img];
setUrlImage(img);
result && result.map(function (img){
let fileReader = new FileReader();
fileReader.readAsDataURL(img);
fileReader.onloadend = async () => {
let res = await fileReader.result;
setArray([...array, res])
};
})
console.log(array)
}
const handleImage = (e) => {
let image = [...e.target.files];
fileBase64(image);
}
<input type="file" multiple={true} onChange={handleImage}/>
Upvotes: 0
Views: 2437
Reputation: 1
Referencing @pedram 's answer, there are a few things I did to make it work for my case.
.map(this.readAsDataURL)
I did .map(fileBase64)
as we want to call this function on every single file when trying to upload multiple files collectively.urls
to an existing array, it should be setArray((prevArray)=>[...prevArray,...urls])
where prevArray is the previous state of the array, due to useState being asynchronous
.Upvotes: 0
Reputation: 16615
Due to this asynchronous
nature, state is being set i.e. push
before data urls
are set in array.
And that's the reason your your array
return empty.
To fix it, you can use create Promise
which gets resolved after load event of each file. And use Promise.all
which would be resolved after each Promise has resolved and then use setArray
:
fileBase64 = (img) => {
return new Promise((resolve, reject) => {
let fileReader = new FileReader();
fileReader.onerror = reject
fileReader.onload = function () {
resolve(fileReader.result)
}
fileReader.readAsDataURL(img)
})
}
handleImage = (e) => {
let image = e.target.files;
Promise.all(Array.from(image).map(this.readAsDataURL))
.then((urls) => {
setArray(urls)
})
.catch((error) => {
console.error(error)
})
}
Upvotes: 3