Reputation: 354
I'm making a file input to select multiple images that can be pre-visualized.
To handle multiple images I put them in an array of the component's state, and map the pre-visualized images.
But when I select the images from the input and set the state with this.setState({imgArray: newArray})
, this.state.array.map(image=><img src={image}/>)
doesn't re-render the selected images.
Code:
export default class posts extends Component {
state = {
fotos: ["/iconos/img.svg"] // If there are not img selected, it renders one image icon
}
onUploadVarious = e => {
let newArray = []
Object.values(e.target.files).map(file => {
let nuevo = new FileReader()
nuevo.onload = event=> newArray.push(event.target.result)
nuevo.readAsDataURL(file)}
)
this.setState({fotos: newArray}) // the state is set correctly
}
}
Render:
<div className=" border rounded" style={{"height":"30%", "overflow":"auto"}}>
{this.state.fotos.map(foto =>
<img src={foto||"/iconos/img.svg"}
id="arch-preview"/>)} // it doesn't re-render when fotos state is changed
</div>
// input
<div className="mt-auto">
<input multiple="multiple" type="file"
onChange={this.onUploadVarious}
className="form-control-file" name="file" />
</div>
Upvotes: 2
Views: 1274
Reputation: 19813
FileReader reads file content asynchronously.
Due to this asynchronous nature, state is being set i.e. this.setState({fotos: newArray})
before data urls are set in newArray
i.e. newArray.push(event.target.result)
.
And that's the reason your selected files aren't showing up.
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 setState
:
readAsDataURL = (file) => {
return new Promise((resolve, reject) => {
const fr = new FileReader()
fr.onerror = reject
fr.onload = function () {
resolve(fr.result)
}
fr.readAsDataURL(file)
})
}
onUploadVarious = (e) => {
Promise.all(Array.from(e.target.files).map(this.readAsDataURL))
.then((urls) => {
this.setState({ fotos: urls })
})
.catch((error) => {
console.error(error)
})
}
This has some good examples of Promises and their executing orders. Also check this about using FileReader with Promise.
Upvotes: 5