Reagieren Sie auf this.setState ist keine Funktion

288

Ich bin neu in React und versuche, eine App zu schreiben, die mit einer API arbeitet. Ich bekomme immer wieder diesen Fehler:

TypeError: this.setState ist keine Funktion

wenn ich versuche, die API-Antwort zu verarbeiten. Ich vermute, dass mit dieser Bindung etwas nicht stimmt, aber ich kann nicht herausfinden, wie ich sie beheben kann. Hier ist der Code meiner Komponente:

var AppMain = React.createClass({
    getInitialState: function() {
        return{
            FirstName: " "
        };
    },
    componentDidMount:function(){
        VK.init(function(){
            console.info("API initialisation successful");
            VK.api('users.get',{fields: 'photo_50'},function(data){
                if(data.response){
                    this.setState({ //the error happens here
                        FirstName: data.response[0].first_name
                    });
                    console.info(this.state.FirstName);
                }

            });
        }, function(){
        console.info("API initialisation failed");

        }, '5.34');
    },
    render:function(){
        return (
            <div className="appMain">
            <Header  />
            </div>
        );
    }
});
Ivan
quelle

Antworten:

348

Der Rückruf erfolgt in einem anderen Kontext. Sie müssen sich bindan , thisum Zugang zum Inneren des Rückruf zu haben:

VK.api('users.get',{fields: 'photo_50'},function(data){
    if(data.response){
        this.setState({ //the error happens here
            FirstName: data.response[0].first_name
        });
        console.info(this.state.FirstName);
    }

}.bind(this));

EDIT: Sieht so aus, als müssten Sie sowohl die initals auch die apiAufrufe binden :

VK.init(function(){
        console.info("API initialisation successful");
        VK.api('users.get',{fields: 'photo_50'},function(data){
            if(data.response){
                this.setState({ //the error happens here
                    FirstName: data.response[0].first_name
                });
                console.info(this.state.FirstName);
            }

        }.bind(this));
    }.bind(this), function(){
    console.info("API initialisation failed");

    }, '5.34');
Davin Tryon
quelle
@TravisReeder, nein. Im Tutorial wird Binden nicht erwähnt.
Tor Haugen
8
Es war wahrscheinlich vor 2,5 Jahren. 😁
Travis Reeder
1
Ich habe die Pfeilfunktion verwendet, um das Problem zu lösen. Vielen Dank für die Hilfe
Tarun Nagpal
Kann jemand näher darauf eingehen, was unter "Rückruf erfolgt in einem anderen Kontext" zu verstehen ist?
SB
135

Mit einer ES6-Pfeilfunktion können Sie die Notwendigkeit von .bind (this) vermeiden.

VK.api('users.get',{fields: 'photo_50'},(data) => {
        if(data.response){
            this.setState({ //the error happens here
                FirstName: data.response[0].first_name
            });
            console.info(this.state.FirstName);
        }

    });
Goodhyun
quelle
1
Das funktioniert gut. Tatsächlich sollte das Schlüsselwort function nicht in einer Datei von es6 angezeigt werden.
JChen___
6
Ihre Antwort hat mir geholfen :-) Mit einer ES6-Klasse und RN 0.34 habe ich zwei Möglichkeiten gefunden, "dies" an eine Rückruffunktion zu binden. 1) onChange={(checked) => this.toggleCheckbox()}, 2) onChange={this.toggleCheckbox.bind(this)}.
Devdanke
Dies ist gut, solange Sie keine alten Browser unterstützen müssen.
Benutzer
Perfekte Lösung
Hitesh Sahu
2
GMsoF, diese beiden Lösungen funktionieren, weil a) wenn Sie dies tun .bind(this), der Wert von thisauf den übergeordneten Kontext gesetzt this.toggleCheckbox()wird, von dem aus aufgerufen wird, andernfalls thiswürde er sich darauf beziehen, wo er tatsächlich ausgeführt wurde. b) Die Fettpfeil-Lösung funktioniert, weil sie den Wert von beibehält. thisSie hilft Ihnen also, indem Sie den Wert von nicht gewaltsam ändern this. thisBezieht sich in JavaScript einfach auf den aktuellen Bereich. Wenn Sie also eine Funktion schreiben, thisist dies diese Funktion. Wenn Sie eine Funktion darin platzieren, thisbefindet sie sich in dieser untergeordneten Funktion. Fette Pfeile halten den Kontext von wo aufgerufen
agm1984
37

Sie können auch einen Verweis auf speichern, thisbevor Sie die apiMethode aufrufen :

componentDidMount:function(){

    var that = this;

    VK.init(function(){
        console.info("API initialisation successful");
        VK.api('users.get',{fields: 'photo_50'},function(data){
            if(data.response){
                that.setState({ //the error happens here
                    FirstName: data.response[0].first_name
                });
                console.info(that.state.FirstName);
            }
        });
    }, function(){
        console.info("API initialisation failed");

    }, '5.34');
},
user2954463
quelle
32

React empfiehlt, dies in allen Methoden zu binden, die dies classanstelle von self verwenden müssen function.

constructor(props) {
    super(props)
    this.onClick = this.onClick.bind(this)
}

 onClick () {
     this.setState({...})
 }

Oder Sie können arrow functionstattdessen verwenden.

uruapanmexicansong
quelle
14

Sie müssen nur Ihre Veranstaltung binden

zum Beispiel

// place this code to your constructor

this._handleDelete = this._handleDelete.bind(this);

// and your setState function will work perfectly

_handleDelete(id){

    this.state.list.splice(id, 1);

    this.setState({ list: this.state.list });

    // this.setState({list: list});

}
g8bhawani
quelle
10

Jetzt hat ES6 eine Pfeilfunktion. Wenn Sie wirklich mit dem Ausdruck bind (this) verwechseln, können Sie die Pfeilfunktion ausprobieren

So mache ich das.

componentWillMount() {
        ListApi.getList()
            .then(JsonList => this.setState({ List: JsonList }));
    }

 //Above method equalent to this...
     componentWillMount() {
         ListApi.getList()
             .then(function (JsonList) {
                 this.setState({ List: JsonList });
             }.bind(this));
 }
Sameel
quelle
8

Sie müssen dies keiner lokalen Variablen zuweisen, wenn Sie die Pfeilfunktion verwenden. Die Pfeilfunktionen werden automatisch gebunden und Sie können sich mit Problemen im Zusammenhang mit dem Bereich fernhalten.

Der folgende Code erläutert die Verwendung der Pfeilfunktion in verschiedenen Szenarien

componentDidMount = () => {

    VK.init(() => {
        console.info("API initialisation successful");
        VK.api('users.get',{fields: 'photo_50'},(data) => {
            if(data.response){
                that.setState({ //this available here and you can do setState
                    FirstName: data.response[0].first_name
                });
                console.info(that.state.FirstName);
            }
        });
    }, () => {
        console.info("API initialisation failed");

    }, '5.34');
 },
Hemadri Dasari
quelle
5

In Reaktion auf es6 / 7 können Sie die Funktion mit der folgenden Pfeilfunktion an den aktuellen Kontext binden, Anfragen stellen und Versprechen wie folgt auflösen:

listMovies = async () => {
 const request = await VK.api('users.get',{fields: 'photo_50'});
 const data = await request.json()
 if (data) {
  this.setState({movies: data})
 }
}

Mit dieser Methode können Sie diese Funktion einfach in componentDidMount aufrufen und die Daten abwarten, bevor Sie Ihr HTML in Ihrer Renderfunktion rendern.

Ich kenne die Größe Ihres Projekts nicht, rate jedoch persönlich davon ab, den aktuellen Status der Komponente zum Bearbeiten von Daten zu verwenden. Sie sollten dafür einen externen Status wie Redux oder Flux oder etwas anderes verwenden.

Quentin Malguy
quelle
5

Verwenden Sie Pfeilfunktionen, da Pfeilfunktionen auf den übergeordneten Bereich verweisen und dieser verfügbar ist. (Ersatz der Bindetechnik)

Pranav Kapoor
quelle
1
Eine großartige prägnante Lösung
Chun
Ich habe zwar das gleiche Problem, um die Methode als Pfeilfunktion im Aufruf aufzurufen, aber ich denke, ich muss die
Statusfunktion
3

Hier ändert sich DIESER Kontext. Verwenden Sie die Pfeilfunktion, um den Kontext der React-Klasse beizubehalten.

        VK.init(() => {
            console.info("API initialisation successful");
            VK.api('users.get',{fields: 'photo_50'},(data) => {
                if(data.response){
                    this.setState({ //the error happens here
                        FirstName: data.response[0].first_name
                    });
                    console.info(this.state.FirstName);
                }

            });
        }, function(){
        console.info("API initialisation failed");

        }, '5.34');
Shubham Gupta
quelle
1

Wenn Sie dies tun und immer noch ein Problem haben, ist mein Problem, dass ich zwei Variablen mit demselben Namen aufgerufen habe.

Ich hatte companiesals Objekt von Firebase gebracht und versuchte dann anzurufen this.setState({companies: companies})- es funktionierte aus offensichtlichen Gründen nicht.

LukeVenter
quelle