web-dev-qa-db-fra.com

React this.setState n'est pas une fonction

Je suis nouveau dans React et j'essaie d'écrire une application fonctionnant avec une API. Je continue à avoir cette erreur:

TypeError: this.setState n'est pas une fonction

quand j'essaie de gérer la réponse de l'API. Je soupçonne que quelque chose ne va pas avec cette reliure, mais je ne vois pas comment la réparer. Voici le code de mon composant:

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

Le rappel est effectué dans un contexte différent. Vous devez bind à this pour pouvoir accéder à l'intérieur du rappel:

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: Il semble que vous deviez lier les appels init et api:

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');
292
Davin Tryon

Vous pouvez éviter le besoin de .bind (this) avec une fonction de flèche ES6.

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

    });
115
goodhyun

vous pouvez également enregistrer une référence à this avant d'appeler la méthode api:

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');
},
37
user2954463

React recommande de lier ceci dans toutes les méthodes qui doivent utiliser ceci de class à la place de self function.

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

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

Ou vous pouvez utiliser arrow function à la place.

18
uruapanmexicansong

Vous avez juste besoin de lier votre événement

par exemple

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

}
10
g8bhawani

Maintenant, les ES6 ont une fonction flèche, c'est vraiment utile si vous confondez vraiment avec bind (cette expression), vous pouvez essayer la fonction flèche

C'est comme ça que je fais.

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

Maintenant, en réagissant avec es6/7, vous pouvez lier une fonction au contexte actuel avec la fonction flèche comme ceci, faire une demande et résoudre des promesses comme ceci:

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

Avec cette méthode, vous pouvez facilement appeler cette fonction dans le composantDidMount et attendre les données avant de rendre votre code HTML dans votre fonction de rendu.

Je ne connais pas la taille de votre projet, mais je vous conseille personnellement de ne pas utiliser l'état actuel du composant pour manipuler les données. Vous devriez utiliser un état externe comme Redux ou Flux ou autre chose pour cela.

5
Quentin Malguy

Vous n'avez pas besoin de l'affecter à une variable locale si vous utilisez la fonction flèche. Les fonctions fléchées prennent automatiquement la liaison et vous pouvez éviter les problèmes liés à l'étendue.

Le code ci-dessous explique comment utiliser la fonction de flèche dans différents scénarios.

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');
 },
5
Hemadri Dasari

Ici, ce contexte est en train de changer. Utilisez la fonction de flèche pour conserver le contexte de la classe React.

        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');
3
Shubham Gupta

Si vous faites cela et avez toujours un problème, mon problème est que j'appelais deux variables du même nom.

J'avais companies comme objet importé de Firebase, puis j'essayais d'appeler this.setState({companies: companies}) - cela ne fonctionnait pas pour des raisons évidentes.

0
LukeVenter