web-dev-qa-db-de.com

Holen Sie sich eine Bildvorschau vor dem Hochladen in React

Viele Beispiele dafür hier, scheinen aber keine Reaktion zu finden. Ich habe es geschafft, die Vanilla-Js zu konvertieren, um zu reagieren, aber einen Fehler zu bekommen.

Die Antwort sieht einfach aus, also gehe ich hier rein:

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

Grundsätzlich zeigen alle Antworten, die ich gesehen habe, so etwas wie ich. Irgendwelche Unterschiede in der React App?

Zur antwort:

 enter image description here

11
Sylar

Kein Unterschied, lesen Sie einfach Ihr Bild, wenn das load-Ereignis abgeschlossen ist. Geben Sie in der Ereignisprozedur load end einfach Ihren Status an:

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>
 )
}
17
Piyush.kapoor

Hier ist eine einfache und funktionierende Lösung, die alle ausgewählten Bilder anzeigt

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. */}
    <img src={this.state.imgSrc} />

    {this.state.imgs && [...this.state.imgs].map((file)=>(
       <img src={URL.createObjectURL(file)} />
    ))}

  </div>
 )
}
2

Wenn wir Cels 'Antwort erweitern und Speicherlecks mit createObjectURL als @ El Anonimo warnt davor vermeiden, könnten wir useEffect verwenden, um das zu erstellen Vorschau anzeigen und bereinigen, nachdem die Komponente wie folgt ausgehängt wurde

useEffect(() => {
   // create the preview
   const objectUrl = URL.createObjectURL(selectedFile)
   setPreview(objectUrl)

   // free memory when ever this component is unmounted
   return () => URL.revokeObjectURL(objectUrl)
}, [selectedFile])

Der vollständige Code könnte ungefähr so ​​aussehen

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

Ich hatte eine verrückte Zeit damit, dies mit mehreren Dateien zum Laufen zu bringen. Wenn also jemand anderes dieses Problem hat, kann es losgehen:

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

Im Wesentlichen wird die for-Schleife aufgelöst, bevor das erste Onload-Ereignis ausgelöst wird, und der Status wird bei jeder Iteration zurückgesetzt. Um dies zu beheben, erstellen Sie einfach ein Array außerhalb der for-Schleife und laden Sie das neue Element. Dies behandelt mehrere Dateien, auch wenn der Benutzer das Dateidialogfeld schließt und später mehr hochlädt, solange der Status nicht zurückgesetzt wurde.

0
Brandon Miller

Da ist meine Lösung. Sehr einfach und leicht zu bedienen.

JSX 

<form onSubmit={this.onSubmit} >      
      <input
         ref="uploadImg"
         type="file"
         name="selectedFile"
         onChange={this._onChange}
        />
</form>

<img src={this.state.imageUrl} />

Und funktion

  _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: ""
        })
    }
}

Und natürlich müssen Sie Folgendes angeben: imageUrl. Dies ist unsere Quelle in jsx.

0
Skylin R