2017-06-07 1 views
0

Ich habe mich seit einigen Tagen umgesehen und kann nicht scheinen, dies zu lösen. Ich habe ein Formular, das einen Datei-Upload über einen XMLHTTPRequestUpload handhabt, ich habe einen onProgress-Callback, den ich aufrufen möchte, und aktualisiere visuell, was auf der Benutzeroberfläche passiert, aber ich kann anscheinend keine erfolgreichen Funktionsaufrufe von "onProgress" ausführen .React ES6 Umfang der Funktionsdeklaration

Ich habe versucht, console.log zu verwenden, um den Bereich zu finden, in dem meine Funktion updateProgress definiert ist. 'this' in der Datei uploadFile onProgress ist die XMLHTTP-Anfrage selbst. Also habe ich es für AddShow versucht, die Klasse selbst. Es spielt keine Fehlermeldung, und listet die Update eine Elementfunktion der Klasse ist, aber wenn man versucht, es zu nennen, habe ich noch

AddShow.updateProgress is not a function 
    at XMLHttpRequestUpload.onProgress 

Also, wo ist Waldo? Wie rufe ich meine Funktion an?

Hier ist meine ganze Reagieren Komponentenklasse:

export class AddShow extends React.Component { 
    constructor(props) { 
    super(props); 

    this.handleTextChange = this.handleTextChange.bind(this); 
    this.uploadFile = this.uploadFile.bind(this); 
    this.updateProgress = this.updateProgress.bind(this); 
    } 

    // function that updates the state of the form input 
    handleTextChange(evt) { 
    this.props.dispatch(actions.changeShowTitleText(evt.target.value)); 
    } 

    //function that show the progress of file upload 
    updateProgress(progress) { 
    progress = Math.floor(progress * 100); 
    //call the dispatch actions to update redux state 
    this.props.dispatch(actions.changeCompleteValue(progress)); 
    this.props.dispatch(actions.changeCompleteText(progress + '%')); 
    this.props.dispatch(actions.changeCompleteARIA(progress + ' percent')); 

    // this.props.complete = progress; 
    // this.props.completeText = progress + '%'; 
    // this.props.ariaCompleteText = progress + ' percent'; 
    } 

    // when 'add show' is pressed, validate form and upload 
    onSubmit(e) { 
    e.preventDefault(); 
    let titleText = this.props.showTitle; 
    if (titleText < 1) { 
     alert("Please provide a Show Title."); 
    } else { 
     // a title has been typed in, call upload with that info. 
     this.uploadFile(titleText); 
    } 
    } 

    //function that finally uploads the file given all the information 
    uploadFile(title) { 
    var uploader = new VimeoUpload({ 
     name: title, 
     file: selectedFile, 
     token: process.env.ACCESS_TOKEN, 
     onProgress: function(data) { 
     var percent = data.loaded/data.total; 
     AddShow.updateProgress(percent); 
     }, 
     onComplete: function(videoId, index) { 
     var url = 'https://vimeo.com/' + videoId 
     } 
    }); 

    uploader.upload(); 
    } 

    // set the global file variable if the input changes 
    handleFileSelect(file) { 
    console.log("These are the files retrieved", file.target.files[0]); 
    selectedFile = file.target.files[0]; 
    } 

    render() { 
    var {dispatch, showTitle, complete, completeText, ariaCompleteText} = this.props; 
    completeText = '0%'; 
    ariaCompleteText = "0 percent"; 

    return(
     <div className="row"> 
     <div className="column small-centered small-11 medium-8 large-6"> 
      <div className="container"> 
      <p>Drag the Video You Want to Upload to Screen</p> 
      <form ref="form" onSubmit={this.onSubmit.bind(this)} className="add-show-form"> 
       <input type="file" placeholder="Select Video File" onChange={(evt) => this.handleFileSelect(evt)}/> 
       <p ref="alertText"></p> 
       <input type="text" value={this.props.showTitle} onChange={this.handleTextChange} placeholder="Show Title"/> 
       <button className="button expanded">Add Show</button> 
      </form> 
      <div className="progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuetext={this.props.ariaCompleteText} aria-valuemax="100"> 
       <span className="progress-meter" style={{width: this.props.complete + '%'}}> 
       <p className="progress-meter-text">{this.props.completeText}</p> 
       </span> 
      </div> 
      </div> 
     </div> 
     </div> 
    ); 
    } 
}; 
+0

hmm das Versuchen, Ihre anonyme Methode zu einem Pfeil Funktion ändern, um die Instanz zu binden, indem Sie 'onProgress: (Daten) => {' und 'Änderung AddShow.updateProgress (Prozent "; zu' this.updateProgress (Prozent); 'Dann kommentieren Sie bitte, welchen Fehler Sie erhalten, wenn überhaupt. – Juan

+0

'AddShow.updateProgress' kann nicht funktionieren, weil' updateProgress' die Methode einer ** Instanz 'von 'AddShow' ist. –

Antwort

0

Sie müssen einen Verweis auf den äußeren Bereich (d. H. Den äußeren Bereich) innerhalb des neuen Bereichs des onProgress-Rückrufs pflegen.Die traditionelle (ES5) Art und Weise, diesen zu Ansatz war es, ein Verweis auf sie in einer Variablen (in der Regel genannt Selbst-) zu erstellen, dann verwenden die Methode innerhalb der Callback zu nennen:

uploadFile(title) { 
    // self now references the outer this 
    var self = this; 
    var uploader = new VimeoUpload({ 
     name: title, 
     file: selectedFile, 
     token: process.env.ACCESS_TOKEN, 
     onProgress: function(data) { 
     var percent = data.loaded/data.total; 

     // we can access the outer scope on self here 
     self.updateProgress(percent); 
     }, 
     onComplete: function(videoId, index) { 
     var url = 'https://vimeo.com/' + videoId 
     } 
    }); 

    uploader.upload(); 
    } 

Da Sie Klassen verwenden, in Wenn Sie Ihren Code verwenden, würde ich davon ausgehen, dass Sie ES6-Code gerne verwenden. Der elegantere Weg, den gleichen Effekt zu erzielen, besteht darin, eine Lambda-Funktion (oder Fettpfeil-Funktion) zu verwenden. Dies bedeutet, dass Ihre Funktionen mit dieser Syntax erklärt:

const someFunction = (anArgument) => { 
    return aResult; 
} 

die (grob) entspricht:

function someFunction(anArgument) { 
    return aResult; 
} 

Der Unterschied ist, dass, wenn Sie eine Funktion mit Lambda-Syntax deklarieren, ein neuer Rahmen nicht erstellt wird . Effektiv ist die this innerhalb der Funktion die gleiche wie die this außerhalb. Wir können dann die upload Handler schreiben wie:

uploadFile(title) { 
    var uploader = new VimeoUpload({ 
     name: title, 
     file: selectedFile, 
     token: process.env.ACCESS_TOKEN, 
     onProgress: (data) => { 
     var percent = data.loaded/data.total; 
     this.updateProgress(percent); 
     }, 
     onComplete: (videoId, index) => { 
     var url = 'https://vimeo.com/' + videoId 
     } 
    }); 

    uploader.upload(); 
    } 
+0

Danke, das hat perfekt funktioniert. Ich habe von der älteren Syntax auf die neue ES6 übersetzt, um der Dokumentation näher zu kommen, und ich glaube, das habe ich verpasst. –

+0

* "Der Unterschied besteht darin, dass beim Deklarieren einer Funktion mit Lambda-Syntax kein neuer Bereich erstellt wird." * Das ist nicht korrekt. "Dies" ist nicht dasselbe wie der Anwendungsbereich. Jeder Funktionsaufruf erstellt einen neuen Bereich. Im Fall einer Pfeilfunktion hat der Bereich jedoch keinen eigenen "this" -Wert. –

0

Die einfachste Lösung für Sie ist, nur einen Pfeil Funktion zu verwenden, die lexikalischen Scoping hat und auf den Kontext der uploadFile scoped werden:

uploadFile(title) { 
    var uploader = new VimeoUpload({ 
    // ... 
    onProgress: (data) => { // <-- use arrow function 
     var percent = data.loaded/data.total; 
     this.updateProgress(percent); 
    } 
    // ... 
} 

Alternativ können Sie den Kontext in einer Variablen speichern und verwenden:

uploadFile(title) { 
    var context = this; // save context 
    var uploader = new VimeoUpload({ 
    // ... 
    onProgress: function(data) { 
     var percent = data.loaded/data.total; 
     context.updateProgress(percent); // use context 
    } 
    // ... 
} 

Sie beachten Sie, dass diese Linie

AddShow.updateProgress(percent); 

Zugriffsversuche auf updateProgress auf die Funktion selbst, nicht der Prototyp, der diese Methode nicht haben.

Wenn Sie die Funktion auf eine statische Weise wie diese aufrufen möchten, müssen Sie sie auf dem Prototyp aufrufen.

0

Lösung 1: Verwenden statische Methode

static updateProgress(progress) { 
 
    progress = Math.floor(progress * 100); 
 
    //call the dispatch actions to update redux state 
 
    this.props.dispatch(actions.changeCompleteValue(progress)); 
 
    this.props.dispatch(actions.changeCompleteText(progress + '%')); 
 
    this.props.dispatch(actions.changeCompleteARIA(progress + ' percent')); 
 
}

Lösung 2: Mit der Pfeilfunktion in upload Methode

uploadFile(title) { 
 
    var uploader = new VimeoUpload({ 
 
    name: title, 
 
    file: selectedFile, 
 
    token: process.env.ACCESS_TOKEN, 
 
    onProgress: function(data) => { 
 
     var percent = data.loaded/data.total; 
 
     // this now refers to your AddShow component 
 
     this.updateProgress(percent); 
 
    }, 
 
    onComplete: function(videoId, index) { 
 
     var url = 'https://vimeo.com/' + videoId 
 
    } 
 
    }); 
 

 
    uploader.upload(); 
 
}

Sie können die Methode addShow nicht direkt von der Klasse aufrufen, da es sich nicht um eine Methode static handelt. Um dieses Problem zu lösen, würde ich vorschlagen, dass Sie entweder ein Schlüsselwort static in Ihrer Methode hinzufügen, so dass Sie es direkt von der Klasse aufrufen können, ohne es instanziieren zu müssen, oder indem Sie in Ihrer uploadFile-Methode eine Pfeilfunktion verwenden.