React this.setState не является функцией
Я новичок в React и пытаюсь написать приложение, работающее с API. Я продолжаю получать эту ошибку:
Ошибка типа: this.setState не является функцией
когда я пытаюсь обработать ответ API. Я подозреваю, что что-то не так с этим связыванием, но я не могу понять, как это исправить. Вот код моего компонента:
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>
);
}
});
Ответы
Ответ 1
Обратный вызов выполняется в другом контексте. Для доступа к обратному вызову необходимо bind
- this
:
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:
Похоже, вам нужно привязать вызовы init
и 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');
Ответ 2
Вы можете избежать необходимости .bind(this) с помощью функции стрелок 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);
}
});
Ответ 3
вы также можете сохранить ссылку на this
перед вызовом метода 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');
},
Ответ 4
React рекомендует связать это во всех методах, которые должны использовать этот class
вместо собственной function
.
constructor(props) {
super(props)
this.onClick = this.onClick.bind(this)
}
onClick () {
this.setState({...})
}
Или вы можете использовать arrow function
вместо этого.
Ответ 5
Теперь ES6 имеет функцию стрелки, это действительно полезно, если вы действительно путаете с выражением bind (this), вы можете попробовать функцию стрелки
Вот как я это делаю.
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));
}
Ответ 6
Вам просто нужно связать ваше мероприятие
для ex-
// 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});
}
Ответ 7
Теперь, реагируя на es6/7, вы можете привязать функцию к текущему контексту с помощью функции стрелки, подобной этой, сделать запрос и разрешить обещания следующим образом:
listMovies = async () => {
const request = await VK.api('users.get',{fields: 'photo_50'});
const data = await request.json()
if (data) {
this.setState({movies: data})
}
}
С помощью этого метода вы можете легко вызвать эту функцию в componentDidMount и подождать данных, прежде чем рендерить ваш HTML в вашей функции рендеринга.
Я не знаю размер вашего проекта, но я лично не рекомендую использовать текущее состояние компонента для манипулирования данными. Вы должны использовать внешнее состояние, такое как Redux или Flux или что-то еще для этого.
Ответ 8
Вам не нужно присваивать это локальной переменной, если вы используете функцию стрелки. Функции стрелок автоматически связываются, и вы можете избежать проблем, связанных с областью действия.
Ниже код объясняет, как использовать функцию стрелки в различных сценариях
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');
},
Ответ 9
Здесь ЭТОТ контекст меняется. Используйте функцию стрелки, чтобы сохранить контекст класса 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');
Ответ 10
Если вы делаете это и у вас все еще есть проблема, моя проблема в том, что я вызывал две переменные с одинаковыми именами.
У меня были companies
как объект, привезенный из Firebase, а затем я пытался вызвать this.setState({companies: companies})
- он не работал по понятным причинам.
Ответ 11
используйте функцию стрелки вместо переходных функций