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