Reputation: 149
I am trying to resize an image before saving it in state so that I can pass it into my payload for upload. The method below handles the resize
export const handleResize = (fileObject) => {
const reader = new FileReader();
const maxUploadFileSize = 1048576;
const imageTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (fileObject.size > maxUploadFileSize && imageTypes.includes(fileObject.type)) {
reader.addEventListener('load', () => {
minifyImg(reader.result, 1000, fileObject.type, (data) => {
const newFile = imageUrlToFile(data, fileObject.name);
return newFile;
});
}, false);
} else {
return fileObject;
}
if (fileObject) {
reader.readAsDataURL(fileObject);
}
};
I am using the function above in my component with code below;
changeHandler(event) {
const uploadFilesArray = Array.prototype.slice.call(event.target.files);
const proofOfIdentityArr = [];
const resizedImages = [];
if (uploadFilesArray.length > 1) {
this.setState({
errText: 'Too many files selected.' +
'You can\'t upload more than one file at a time.',
});
setTimeout(() => {
this.setState({
errText: '',
});
}, 5000);
return;
}
uploadFilesArray.forEach((file) => {
const fileUrl = window.URL.createObjectURL(file);
const reader = new FileReader();
const fileData = {
fileUrl,
name: file.name,
};
reader.onload = () => {
fileData.imagePreviewUrl = reader.result;
};
reader.readAsDataURL(file);
proofOfIdentityArr.push(fileData);
//importing and using the resizing function
const newFile = utils.handleResize(file));
resizedImages.push(newFile);
});
this.setState({
proofOfIdentity: proofOfIdentityArr,
uploadFilesArray: resizedImages,
});
}
The function resizes the image but my problem is that it is asynchronous and returns with a resized image late after the state has already been set, so I get an undefined. How can I make my changeHandler function wait for the resize function to return its value before proceeding.
Upvotes: 0
Views: 441
Reputation: 2137
First of all your handleResize
function doesn't always return value. But generally what you need to do is to use callback in your handleResize
(when image will get resize - handleResize
will call passed function aka callback), instead of returning new image from there.
handleResize:
export const handleResize = (fileObject, callback) => {
const reader = new FileReader();
const maxUploadFileSize = 1048576;
const imageTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (fileObject.size > maxUploadFileSize && imageTypes.includes(fileObject.type)) {
reader.addEventListener('load', () => {
minifyImg(reader.result, 1000, fileObject.type, (data) => {
const newFile = imageUrlToFile(data, fileObject.name);
callback(newFile); //Invoke callback with new resized image
});
}, false);
} else {
callback(fileObject); //Invoke callback with passed image (size is OK)
}
if (fileObject) {
reader.readAsDataURL(fileObject);
}
};
changeHandler:
changeHandler(event) {
const uploadFilesArray = Array.prototype.slice.call(event.target.files);
const proofOfIdentityArr = [];
const resizedImages = [];
if (uploadFilesArray.length > 1) {
this.setState({
errText: 'Too many files selected.' +
'You can\'t upload more than one file at a time.',
});
setTimeout(() => {
this.setState({
errText: '',
});
}, 5000);
return;
}
uploadFilesArray.forEach((file) => {
const fileUrl = window.URL.createObjectURL(file);
const reader = new FileReader();
const fileData = {
fileUrl,
name: file.name,
};
reader.onload = () => {
fileData.imagePreviewUrl = reader.result;
};
reader.readAsDataURL(file);
proofOfIdentityArr.push(fileData);
//importing and using the resizing function
// here we are using the callback - and adding new "resized" image to the state
utils.handleResize(file,(resizedImage) => {
this.setState((state) => { return { uploadFilesArray :
[...state.uploadFilesArray, resizedImage]} });
});
//resizedImages.push(newFile);
});
this.setState({
proofOfIdentity: proofOfIdentityArr //,
//uploadFilesArray: resizedImages, // - not here
});
}
Upvotes: 1