Reputation: 101
I'm trying to implement Dropzone on my app but I can't preview photos if they are drop as a multiple input. If I add them one by one it works fine but if I select multiple only the first one gets rendered.
This is my onDrop function
onDropGeneral = (currentGeneralPhoto) => {
let index;
for (index = 0; index < currentGeneralPhoto.length; ++index) {
const file = currentGeneralPhoto[index];
this.setState({
previewGeneralPhotos: this.state.previewGeneralPhotos.concat(file)
});
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (event) => {
console.log('URL: ', event.target.result);
this.setState({
generalPhotos: this.state.generalPhotos.concat([{ base64: event.target.result }])
});
};
}
}
and this is my render method:
<h2>Dropped files</h2>
{this.state.previewGeneralPhotos.length > 0 ? <div>
<h2>Preview {this.state.previewGeneralPhotos.length} files...</h2>
<div>{this.state.previewGeneralPhotos.map((file) => <img src={file.preview} alt="preview failed" />)}</div>
</div> : null}
<h2> Upload {this.state.generalPhotos.length} Files </h2>
the Upload count is showing the right size of the array but the Preview count only counts the 1st photo dropped
Upvotes: 2
Views: 2547
Reputation: 4423
So your issue is because setState
can be asynchronous. You should use the function callback for setState
as follows in your onDropGeneral
function:
this.setState(({ previewGeneralPhotos }) => ({
previewGeneralPhotos: previewGeneralPhotos.concat(file)
}))
This will make sure you don't accidentally overwrite the previous value of previewGeneralPhotos
and you actually add to the existing array as you intend.
A couple of other suggestions:
img
elements have a key.onDropGeneral
method is called. You could attach an event listener for the 'load' event in componentDidMount
and remove that listener in componentWillUnmount
. At the very least, it's probably best to attach that event listener before calling reader.readAsDataURL
.Upvotes: 1