Javascript 在 React 中上传之前获取图像预览
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38049966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get image preview before uploading in React
提问by Sylar
Many examples of this on here but can't seem to find any for react. I have managed to convert the vanilla js to react but getting an error.
这里有很多这样的例子,但似乎找不到任何反应。我已经设法将 vanilla js 转换为反应但出现错误。
The answer looks simple enough so here I go in react:
答案看起来很简单,所以我在这里做出反应:
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>
)
};
Basically all answers I have seen show something like what I have. Any difference in React app?
基本上我看到的所有答案都显示了我所拥有的。React 应用程序有什么不同吗?
Regarding answer:
关于答案:
回答by Piyush.kapoor
No difference, just read your image when the load
event finishes. After the load end
event handler just set your state:
没有区别,只需在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>
)
}
回答by Jay Wick
Extending on Cels' answer, and avoiding memory leaks with createObjectURL
as @El Anonimo warns about, we could use useEffect
to create the preview and clean up after the component unmounts like so
扩展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])
The full code could look something like this
完整的代码看起来像这样
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>
)
}
回答by Cels
Here is a simple and working solution which displays all selected images
这是一个简单而有效的解决方案,它显示所有选定的图像
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>
)
}
回答by Brandon Miller
I had a crazy time trying to get this to work with multiple files, so if anyone else is having this problem, here you go:
我有一段疯狂的时间试图让它处理多个文件,所以如果其他人遇到这个问题,你去吧:
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);
}
};
Essentially the for loop resolves before even the first onload event fires, resetting the state every time it iterates. To resolve this just make an array outside of the for loop and push the new item to it onload. This will handle multiple files even if the user closes the file dialog and later chooses to upload more, as long as state hasn't been reset.
本质上,for 循环甚至在第一个 onload 事件触发之前就解决了,每次迭代时都会重置状态。要解决这个问题,只需在 for 循环之外创建一个数组并将新项目推送到它。即使用户关闭文件对话框并稍后选择上传更多文件,只要状态尚未重置,这也将处理多个文件。
回答by Skylin R
There is my solution. Very simple and easy to use.
有我的解决方案。非常简单易用。
JSX
JSX
<form onSubmit={this.onSubmit} >
<input
ref="uploadImg"
type="file"
name="selectedFile"
onChange={this._onChange}
/>
</form>
<img src={this.state.imageUrl} />
And function
和功能
_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: ""
})
}
}
And of course You need to have state like imageUrl
which is our src in jsx.
当然,你需要有状态,比如imageUrl
我们在 jsx 中的 src。
回答by Jonata
-- Constructor
-- 构造函数
constructor(props) {
super(props);
this.state = {
imgRef: ""
};
}
-- Function
- 功能
filePreview(e) {
const file = e.target.files[0];
this.setState({
imgRef: URL.createObjectURL(file)
});
}
-- Html
-- html
<input
type="file"
name="photo"
onChange={this.fileSelectHandler.bind(this)}
/>
<img src={this.state.imgRef} />
回答by Gautam Paladiya
URL.createObjectURL(file) short and fine solution
URL.createObjectURL(file) 短而精的解决方案