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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:01:42  来源:igfitidea点击:

Get image preview before uploading in React

javascriptjqueryreactjs

提问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:

关于答案:

enter image description here

在此处输入图片说明

回答by Piyush.kapoor

No difference, just read your image when the loadevent finishes. After the load endevent 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 createObjectURLas @El Anonimo warns about, we could use useEffectto 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 imageUrlwhich 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) 短而精的解决方案