Связывание контекста при вызове метода ES6. Как получить доступ к объекту из метода, называемого обратным вызовом?
Я пытаюсь обернуть голову вокруг синтаксиса для классов в ES6. В то же время обучение Ткань уроженец через Бонни Эйзенмана Изучение Реагирующей Нации.
Я столкнулся с проблемой доступа к this
в обратном вызове, когда этот обратный вызов является методом класса. Я знаю, что проблемы вокруг lexical this
в обратных вызовах многократно возникали в StackOverflow. Например, в
Как получить доступ к правильному контексту` this` внутри обратного вызова?.
Основываясь на моем исследовании онлайн, я нашел решение. Но я не уверен, что это правильный способ сделать это в ES6.
Моя проблема возникла, когда я попробовал следующее:
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: ''
};
}
_handleTextChange(event) {
console.log(event.nativeEvent.text);
this.setState({zip: event.nativeEvent.text})
}
render() {
return (
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
);
}
}
(Которое я только немного изменил из примера в книге, чтобы соответствовать синтаксису класса ES6 и синтаксису import/export вместо Require.)
Если я это сделаю, this
в _handleTextChange
будет undefined (не может прочитать свойство 'setState' из undefined). Я был удивлен этим. Исходя из других языков OO, я интерпретирую, как будто этот метод ведет себя больше, как если бы это был статический метод.
Я смог решить это, пропустив метод класса и используя обозначение стрелки. onSubmitEditing={event => this.setState({name: event.nativeEvent.text})}
. Что хорошо работает. У меня нет проблем или смущения.
Я действительно хочу разобраться, как вызвать метод класса. После честного исследования мне удалось сделать это, выполнив следующие действия: onSubmitEditing={this._handleTextChange.bind(this)}
. Возможно, я неправильно понял фундаментальный аспект JavaScript (я новичок в JS), но для меня это кажется совершенно безумным. Нет ли способа доступа к контексту объекта из одного метода без явной привязки объекта обратно к... его собственному методу в том месте, где он вызывается?
Я также попытался добавить var self = this;
в конструктор и вызвать self.setState
в _handleTextChange
. Но не удивился, обнаружив, что это не сработало.
Каков правильный способ доступа к объекту из одного из его методов, когда он вызывается как обратный вызов?
Ответы
Ответ 1
Способ React.createClass(ES5) для создания класса имеет встроенную функцию, которая автоматически привязывает все методы к this
. Но при введении classes
в ES6 и миграции React.createClass, они обнаружили, что это может быть немного запутанным для разработчиков JavaScript, которые не используются для этой функции в других классах, или это может сбивать с толку, когда они переходят из React в другие классы.
Итак, они решили не иметь этого встроенного в модель класса React. Вы все еще можете явно использовать методы prebind в своем конструкторе, если хотите, чтобы
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: ''
};
this._handleTextChange = this._handleTextChange.bind(this); //Binding to `this`
}
_handleTextChange(event) {
console.log(event.nativeEvent.text);
this.setState({zip: event.nativeEvent.text})
}
Но у нас всегда есть простой способ избежать этой предобработки. Да! Ты понял. Функции стрелок.
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: ''
};
}
_handleTextChange = event => {
console.log(event.nativeEvent.text);
this.setState({zip: event.nativeEvent.text})
}
render() {
return (
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
);
}
}
Кстати, это все касается Реактива. Класс ES6 всегда имеет способ доступа к контексту объекта изнутри метода без явного привязывания объекта к его собственному методу.
class bindTesting {
constructor() {
this.demo = 'Check 1';
}
someMethod() {
console.log(this.demo);
}
callMe() {
this.someMethod();
}
}
let x = new bindTesting();
x.callMe(); //Prints 'Check 1';
Но это не выводит "Check 1", если мы будем называть его в выражении JSX.
EDIT:: Как упоминалось в @Oka, функции стрелок в телах классов являются функциями ES7 + и доступны в Compiler/polyfills, таких как babel. Если вы не используете транспилятор, который поддерживает эту функцию, мы можем просто привязать к this
, как упоминалось выше, или написать новый базовый компонент (это плохая идея)
class BaseComponent extends React.Component {
_bind(...methods) {
methods.forEach( (method) => this[method] = this[method].bind(this) );
}
}
class ExampleComponent extends BaseComponent {
constructor() {
super();
this._bind('_handleTextChange', '_handleClick');
}
// ...
}
Ответ 2
Прерываясь от ES6 и реагируя на мгновение, в обычном старом JavaScript, когда вы передаете метод объекта вокруг него, это просто ссылка на саму функцию, а не на объект и функцию.
Любая вызывающая функция может использовать неявный this
, вызывая функцию обычно или может даже выбрать изменение контекста с помощью .call
и .apply
, или .bind
.
var O = {
foo: function () {
console.log(this);
},
bar: 51
};
O.foo(); // `this` is O, the implicit context, inferred from the object host
var foo = O.foo;
foo(); // `this` is is the global object, or undefined in Strict Mode
Ответ 3
Возможно, я неправильно понял фундаментальный аспект JavaScript (я новичок в JS), но мне это кажется совершенно безумным. Нет ли способа доступа к контексту объекта из одного метода без явной привязки объекта обратно к... его собственному методу в том месте, где он вызывается?
Ну, "методы" не принадлежат объектам в javascript. Все функции являются первоклассными значениями (объектами), а не "частью" объекта или класса.
Связывание this
value происходит, когда вызывается функция, в зависимости от того, как вызывается функция. Функциональный вызов с нотной записью метода имеет свой this
, установленный для принимающего объекта, вызов прослушивателя событий имеет свой this
, установленный для текущего целевого объекта, а обычный вызов функции имеет только undefined
.
Если вы обращаетесь к методу в экземпляре, это действительно просто стандартный доступ к свойствам наследования наследования, который дает функцию, которая затем вызывается и динамически привязана к получателю.
Если вы хотите вызвать функцию как метод в экземпляре, когда она является прослушивателем событий, вам нужно явно создать функцию, которая делает это - метод "bound". В ES6 обозначение стрелки обычно предпочтительнее для этого.