【问题标题】:Get image preview before uploading in React在 React 中上传之前获取图像预览
【发布时间】:2016-10-29 05:33:54
【问题描述】:

这里有很多这样的例子,但似乎找不到任何反应。我已经设法将香草 js 转换为做出反应,但得到了an error

答案看起来很简单,所以我在这里做出反应:

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 应用有什么不同吗?

关于答案:

【问题讨论】:

    标签: javascript jquery reactjs


    【解决方案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>
     )
    }
    

    【讨论】:

    • 谢谢。 result 在散列中为空,但在外部时不为空。有道理? reader 显示哈希,但 result 为空。见帖子中的图片。
    • 在函数中它可能是空的,因为我们已经绑定了这个loadend函数,调试了render函数,并检查了它应该更新的状态
    • 我发现了您代码中的错误。将reader.result; 更改为[reader.result] 谢谢!!
    • 更新你的答案,所以我总结了这个问题。谢谢。
    • 这个答案很老了,但我想分享一下我遇到的,不需要做所有初始化fileReader & 东西的繁琐工作,你可以const file = e.target.files[0]; if (!file) return; // else it will throw an parse error const url = URL.createObjectURL(file); url 可以绑定到&lt;img src={url} /&gt; 像这样。希望有人觉得这很有帮助。
    【解决方案2】:

    Cels' answer 上进行扩展,并避免将createObjectURL 用作@El Anonimo warns about 的内存泄漏,我们可以使用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>
        )
    }
    

    【讨论】:

    • 如何提供删除选项?
    • 嘿,2020 年了!不错!
    • 这里的关键是URL.createObjectURL(selectedFile)
    • 嘿@Jay Wick URL.createObjectURL 被弃用了吗?看到这个链接:developers.google.com/web/updates/2018/10/…
    • 2021 年 11 月仍在工作。这为我减轻了很多压力。亲爱的朋友
    【解决方案3】:

    拜托这对我来说很完美

    state = {
      img: logo
    }
    
    handleChangeImage = e => {
      this.setState({[e.target.name]: URL.createObjectURL(e.target.files[0])})
    }
    
    <input type="file" id="img" name="img" accept="image/*" className="w-100" onChange={this.handleChangeImage}/>
    
    <img src={this.state.img} alt="img"/>
    

    查看链接了解更多详情https://medium.com/@650egor/react-30-day-challenge-day-2-image-upload-preview-2d534f8eaaa

    【讨论】:

    • 哇,我被FileReader() 卡住了大约 2 个小时来预览多张照片,实际上URL.createObjectURL 非常简单并且支持所有浏览器。
    【解决方案4】:

    这是一个显示所有选定图像的简单且有效的解决方案

    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>
     )
    }
    

    【讨论】:

    • 请记住,每次createObjectURL(file) 生成的 URL 都会保留在内存中。为了防止内存泄漏调用URL.revokeObjectURL(&lt;previously_created_ objectUrl&gt;) 从内存中删除旧图像 URL。发现于medium.com/@scyrizales/…
    【解决方案5】:

    试试这个多重上传和预览:

    import React,{useState} from 'react';
    import { makeStyles } from '@material-ui/core/styles';
    import Button from '@material-ui/core/Button';
    import IconButton from '@material-ui/core/IconButton';
    import PhotoCamera from '@material-ui/icons/PhotoCamera';
     
    
    const useStyles = makeStyles((theme) => ({
      root: {
        '& > *': {
          margin: theme.spacing(1),
        },
      },
      input: {
        display: 'none',
      },
    }));
    
    export default function UploadButtons() {
      const classes = useStyles();
      const [files,setFile]=useState([]);
      const handlerFile=(e)=>{    
        console.log(e.target.files);
        
        let allfiles=[]
       for(let i=0;i<e.target.files.length;i++){
        allfiles.push(e.target.files[i]);
       }
        if(allfiles.length>0){
          setFile(allfiles);  
        }
      };
      return (
        <div className={classes.root}>
            {files.map((file, key) => {
                                return (
                                    <div key={key} className="Row">
                                        <span className="Filename">
                                            {file.name}
                                            <img src={URL.createObjectURL(file)}  alt={file.name} />
                                        </span>
                                    </div>
                                )
                            })}
          <input
            accept="image/*"
            className={classes.input}
            id="contained-button-file"
            multiple
            type="file"
            onChange={handlerFile}
          />
          <label htmlFor="contained-button-file">
            <Button variant="contained" color="primary" component="span">
              Upload
            </Button>
          </label> 
          
      );
    }
    

    【讨论】:

      【解决方案6】:

      有我的解决方案。非常简单易用。

      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 这样的状态,这是我们在 jsx 中的 src。

      【讨论】:

      【解决方案7】:

      我花了很长时间试图让它与多个文件一起工作,所以如果其他人有这个问题,你去吧:

      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 循环之外创建一个数组并将新项目推送到它 onload。这将处理多个文件,即使用户关闭文件对话框并稍后选择上传更多文件,只要状态尚未重置。

      【讨论】:

        【解决方案8】:

        您可以使用 base64 并在 img src 中使用该结果。这里我使用的是打字稿,但是你可以用纯 JS 使用相同的逻辑

        (file: Blob):Promise< string | ArrayBuffer | null> => new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result);
            reader.onerror = error => reject(error);
        }),
        

        【讨论】:

          【解决方案9】:

          这是基于@Mohammed 的回答以及如何使用它的示例

          const loadImage = (file: Blob) =>
            new Promise<string>((resolve, reject) => {
              const reader = new FileReader();
              reader.readAsDataURL(file);
              reader.onload = () =>
                typeof reader.result === "string" ? resolve(reader.result) : reject(reader.result);
              reader.onerror = error => reject(error);
            });
          
          export const FilePreview: React.FC<{ file: File }> = ({ file }) => {
            const [imageUrl, setImageUrl] = React.useState<string | undefined>(undefined);
            React.useEffect(() => {
              loadImage(file).then(setImageUrl);
            }, [file]);
            return (
              <div>
                {imageUrl && <img src={imageUrl} alt={file.name} />}
                <div>{file.name}</div>
              </div>
            );
          };
          

          【讨论】:

            【解决方案10】:
             1. image with preview and close button
            
            import React,{useState} from "react";
            
            export default function App() {
              const  [preview,setPreview] = useState([]);
            
              const maxLength = 3;
            
            
            
              const onSelectFile=(e)=>{
                  for (var i=0;i < e.target.files.length;i++){
                    arrayofFiles.push(e.target.files[i]);
                    
                }
                
              let images = [];
              arrayofFiles.map((e)=>{
              const ImageUrl =  URL.createObjectURL(e);
              images.push(ImageUrl)
                  
              })
              setPreview(images)
              }
            
            
            
              const removeImageFromArray=(e)=>{
                const index = e.target.id;
                let newPreview = [...preview];
            
                newPreview.splice(index,1);
                setPreview(newPreview);
              }
              return (
                <div className="App">
                  <h1>Image view and close</h1>
                  <input type="file" name="file" multiple onChange={onSelectFile}/>
                {preview.map((img,index)=>
                  (
                    <div key={index}>
                     <img src={img} id={index} alt="pic1" width="250" height="250" />
                       <button
                          id={index}
                          key={index}
                          onClick={(e) => {
                            removeImageFromArray(e);
                          }}
                        >
                          Close
                        </button>
            
                    </div>
                  )  
                )}
                 </div>
              );
            }
            

            【讨论】:

              【解决方案11】:

              -- 构造函数

              constructor(props) {
                super(props);
                this.state = {
                   imgRef: ""
                };
              }
              

              -- 功能

              filePreview(e) {
                  const file = e.target.files[0];
                  this.setState({
                      imgRef: URL.createObjectURL(file)
                  });
              }
              

              -- html

              <input
                 type="file"
                 name="photo"
                 onChange={this.fileSelectHandler.bind(this)}
              />
              <img src={this.state.imgRef} />
              

              【讨论】:

                【解决方案12】:

                URL.createObjectURL(文件) 短而精的解决方案

                【讨论】:

                  猜你喜欢
                  • 2011-05-26
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-09-04
                  相关资源
                  最近更新 更多