Ошибка доступа к состоянию внутри setInterval в React.js

Я пытаюсь получить доступ к состоянию компонента внутри setInterval таким образом, но он не работает:

componentDidMount: function() {
    setInterval(function() {
      console.log(this.state);
    }, 3000);
}

Однако, если я помещаю функцию обратного вызова в отдельный компонентный метод, он отлично работает:

displayState: function() {
  console.log(this.state)
}
componentDidMount: function() {
    setInterval(this.displayState(), 3000);
}

Любая идея, почему это происходит? Я бы предпочел использовать первый вариант.

Ответ 1

В первом примере this выходит за пределы области действия при срабатывании функции обратного вызова. Один из способов решения этой проблемы - использовать переменную:

componentDidMount: function() {
    var self = this;
    setInterval(function() {
      console.log(self.state);
    }, 3000);
}

Проблема с вашей второй попыткой заключается в том, что вы вызываете функцию немедленно и передаете результат выполнения функции setInterval. Вы должны передать эту функцию, соблюдая привязку this:

componentDidMount: function() {
    setInterval(this.displayState.bind(this), 3000);
}

Чтобы пояснить, разница между этим подходом и вторым примером в вашем вопросе заключается в том, что здесь функция передается в setInterval (потому что function.bind() возвращает функцию).

Поскольку вы используете React.createClass, нет необходимости управлять привязкой this самостоятельно, из-за autobind. Это означает, что вы можете просто передать эту функцию, а this будет такой же, как в исходном контексте:

componentDidMount: function() {
    setInterval(this.displayState, 3000);
}

Конечно, наиболее подходящий подход зависит от того, предпочитаете ли вы использовать анонимную функцию или нет.

Ответ 2

Вам нужно выполнить обработчик интервала с правильной ссылкой на this. Использовать Reacts автообновление для решения cleasest IMO:

displayState: function() {
  console.log(this.state)
},
componentDidMount: function() {
    setInterval(this.displayState, 3000)
}

Или используйте bind, если вы хотите анонимную функцию:

componentDidMount: function() {
    setInterval(function() {
        console.log(this.state)
    }.bind(this), 3000)
}