Получите предварительный просмотр изображения перед загрузкой в React
Много примеров этого здесь, но не могу найти ни одного для реакции. Мне удалось преобразовать vanilla js, чтобы он реагировал, но получил ошибку.
Ответ выглядит достаточно простым, поэтому здесь я реагирую:
getInitialState: function(){
return{file: []}
},
_onChange: function(){
// Assuming only image
var file = this.refs.file.files[0];
var reader = new FileReader();
var url = reader.readAsDataURL(file);
console.log(url) // Would see a path?
// TODO: concat files for setState
},
render: function(){
return(
<div>
<form>
<input
ref="file"
type="file"
name="user[image]"
multiple="true"
onChange={this._onChange}/>
</form>
{/* Only show first image, for now. */}
<img src={this.state.file[0} />
</div>
)
};
В основном все ответы, которые я видел, показывают что-то вроде того, что у меня есть. Есть ли разница в приложении React?
Относительно ответа:
![enter image description here]()
Ответы
Ответ 1
Нет разницы, просто прочитайте свое изображение, когда закончится событие load
. В обработчике событий load end
просто укажите ваше состояние:
getInitialState: function(){
return{file: []}
}
_onChange: function(){
// Assuming only image
var file = this.refs.file.files[0];
var reader = new FileReader();
var url = reader.readAsDataURL(file);
reader.onloadend = function (e) {
this.setState({
imgSrc: [reader.result];
})
}.bind(this);
console.log(url) // Would see a path?
// TODO: concat files
},
render: function(){
return(
<div>
<form>
<input
ref="file"
type="file"
name="user[image]"
multiple="true"
onChange={this_onChange}/>
</form>
{/* Only show first image, for now. */}
<img src={this.state.imgSrc} />
</div>
)
}
Ответ 2
Вот простое и рабочее решение, которое отображает все выбранные изображения
getInitialState: function(){
return{file: []}
}
_onChange: (event)=>{
this.setState({
imgs: event.target.files
})
},
render: function(){
return(
<div>
<form>
<input
ref="file"
type="file"
name="user[image]"
multiple="true"
onChange={this._onChange}/>
</form>
{/* Display all selected images. */}
{this.state.imgs && [...this.state.imgs].map((file)=>(
<img src={URL.createObjectURL(file)} />
))}
</div>
)
}
Ответ 3
Расширяя ответ Cels и избегая утечек памяти с помощью createObjectURL
, когда @El Anonimo предупреждает о, мы могли бы использовать useEffect
для создания предварительного просмотра и очистки после размонтирования компонента вот так
useEffect(() => {
// create the preview
const objectUrl = URL.createObjectURL(selectedFile)
setPreview(objectUrl)
// free memory when ever this component is unmounted
return () => URL.revokeObjectURL(objectUrl)
}, [selectedFile])
Полный код может выглядеть примерно так
export const ImageUpload = () => {
const [selectedFile, setSelectedFile] = useState()
const [preview, setPreview] = useState()
// create a preview as a side effect, whenever selected file is changed
useEffect(() => {
if (!selectedFile) {
setPreview(undefined)
return
}
const objectUrl = URL.createObjectURL(selectedFile)
setPreview(objectUrl)
// free memory when ever this component is unmounted
return () => URL.revokeObjectURL(objectUrl)
}, [selectedFile])
const onSelectFile = e => {
if (!e.target.files || e.target.files.length === 0) {
setSelectedFile(undefined)
return
}
// I've kept this example simple by using the first image instead of multiple
setSelectedFile(e.target.files[0])
}
return (
<div>
<input type='file' onChange={onSelectFile} />
{selectedFile && <img src={preview} /> }
</div>
)
}
Ответ 4
Есть мое решение. Очень простой и простой в использовании.
JSX
<form onSubmit={this.onSubmit} >
<input
ref="uploadImg"
type="file"
name="selectedFile"
onChange={this._onChange}
/>
</form>
<img src={this.state.imageUrl} />
И функция
_onChange = (e) => {
const file = this.refs.uploadImg.files[0]
const reader = new FileReader();
reader.onloadend = () => {
this.setState({
imageUrl: reader.result
})
}
if (file) {
reader.readAsDataURL(file);
this.setState({
imageUrl :reader.result
})
}
else {
this.setState({
imageUrl: ""
})
}
}
И, конечно, вам нужно иметь состояние типа imageUrl
, которое является нашим src в jsx.
Ответ 5
Я безумно пытался заставить это работать с несколькими файлами, так что, если у кого-то еще возникла эта проблема, вот вам:
const onFileChange = e => {
e.preventDefault();
const filesList = e.target.files;
if (filesList.length === 0) return;
//Spread array to current state preview URLs
let arr = [...data.imagePreviewUrls];
for (let i = 0; i < filesList.length; i++) {
const file = filesList[i];
const reader = new FileReader();
reader.onload = upload => {
//push new image to the end of arr
arr.push(upload.target.result);
//Set state to arr
setData({
...data,
imagePreviewUrls: arr
});
};
reader.readAsDataURL(file);
}
};
По сути, цикл for разрешается до того, как сработает даже первое событие onload, сбрасывая состояние при каждой итерации. Чтобы решить эту проблему, просто создайте массив вне цикла for и загрузите новый элемент в него. Это будет обрабатывать несколько файлов, даже если пользователь закроет диалоговое окно файла, а затем решит загрузить больше, если состояние не было сброшено.