- Оригинальный адрес:This is why we need to bind event handlers in Class Components in React
- Оригинальный автор:Saurabh Misra
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:whuzxq
- Корректор:sunhaokk,dandyxu
Источник фонового изображения взят изKaley Dykstraи опубликовано вUnsplashвыше изображение исходного кода генерируется изcarbon.now.sh.
При работе с React вы неизбежно столкнетесь с контролируемыми компонентами и обработчиками событий. В конструкторе пользовательского компонента нам нужно использовать.bind()для привязки метода к экземпляру компонента.
class Foo extends React.Component{
constructor( props ){
super( props );
this.handleClick = this.handleClick.bind(this);
}
handleClick(event){
// 你的事件处理逻辑
}
render(){
return (
<button type="button"
onClick={this.handleClick}>
Click Me
</button>
);
}
}
ReactDOM.render(
<Foo />,
document.getElementById("app")
);
В этой статье мы рассмотрим, почему.
если ты прав.bind()Пока не знаю, рекомендую прочитатьэта статья.
Виноват JavaScript, а не реакция
Что ж, обвинение звучит жестко. Если мы будем следовать синтаксису React и JSX, нам не нужно этого делать. На самом деле привязатьthisэто синтаксис в JavaScript.
Давайте посмотрим, что произойдет, если мы не привяжем обработчик события к экземпляру компонента:
class Foo extends React.Component{
constructor( props ){
super( props );
}
handleClick(event){
console.log(this); // 'this' 值为 undefined
}
render(){
return (
<button type="button" onClick={this.handleClick}>
Click Me
</button>
);
}
}
ReactDOM.render(
<Foo />,
document.getElementById("app")
);
Если вы запустите этот код, нажмите кнопку «Click Me» и проверьте свою консоль, вы увидите печать консолиundefined, это значениеhandleClick()Значение this внутри метода.handleClick()метод, кажется, естьпотерянныйЕго контекст (экземпляр компонента), который является значением this.
Как эта привязка работает в JavaScript
Как я уже упоминал выше, это JavaScriptthisМеханизм связывания вызывает вышеперечисленное. Я не буду вдаваться в подробности в этом посте, ноэта статьяМожет помочь вам узнать, как эта привязка работает в JavaScript.
К нашему обсуждению имеет отношение то, что внутри функцииthisЗначение зависит от того, как была вызвана функция.
привязка по умолчанию
function display(){
console.log(this); // 'this' 将指向全局变量
}
display();
Это обычный вызов функции. при этих обстоятельствах,display()в методеthisУказывает на окно или глобальный объект в нестрогом режиме. В строгом режиме,thisнаправлениеundefined.
неявное связывание
var obj = {
name: 'Saurabh',
display: function(){
console.log(this.name); // 'this' 指向 obj
}
};
obj.display(); // Saurabh
Когда мы вызываем эту функцию с объектом obj,display()внутри методаthisнаправлениеobj.
Однако, когда мы присваиваем эту ссылку на функцию какой-либо другой переменной и используем эту новую ссылку на функцию для вызова функции, мы находимся вdisplay()получил разныеthisстоимость.
var name = "uh oh! global";
var outerDisplay = obj.display;
outerDisplay(); // uh oh! global
В приведенном выше примере, когда мы вызываемouterDisplay()Когда мы не указываем конкретный объект контекста. Это чистая функция звонка без объекта владельца. при этих обстоятельствах,display()Внутреннийthisзначение возвращается кпривязка по умолчанию. теперь этоthisуказывает на глобальный объект, в строгом режиме указывает наundefined.
При передаче этих функций в качестве обратных вызовов другой пользовательской функции, функции сторонней библиотеки или чему-то подобномуsetTimeoutКогда используются такие встроенные функции JavaScript, упомянутый выше метод оценки особенно полезен.
Рассмотрите приведенный ниже код при настройкеsetTimeoutметод и вызовите его, что произойдет.
//setTimeout 的虚拟实现
function setTimeout(callback, delay){
//等待 'delay' 数个毫秒
callback();
}
setTimeout( obj.display, 1000 );
Мы можем проанализировать это при вызовеsetTimeout, JavaScript внутренне преобразуетobj.displayназначить параметрcallback.
callback = obj.display;
Как мы анализировали ранее, эта операция присваивания приводит кdisplay()Функция теряет свой контекст. когда эта функция заканчивается вsetTimeoutКогда функция вызывается,display()Внутреннийthisзначение будет возвращено впривязка по умолчанию.
var name = "uh oh! global";
setTimeout( obj.display, 1000 );
// uh oh! global
явная привязка
Чтобы избежать этого, мы можем использоватьявный метод привязки,Будуthisзначение черезbind()Методы привязаны к функциям.
var name = "uh oh! global";
obj.display = obj.display.bind(obj);
var outerDisplay = obj.display;
outerDisplay();
// Saurabh
Теперь, когда мы звонимouterDisplay()час,thisзначение указывает наdisplay()Внутреннийobj.
Мы немедленноobj.displayпередается непосредственно в функцию в качестве параметра обратного вызова,display()Внутреннийthisтакже правильно укажет наobj.
Воссоздайте сцену, используя только JavaScript
В начале этой статьи мы создали класс с именемFooРеагировать на компоненты. если мы неthisПривязать к событию, значение в событии станетundefined.
Как я объяснил выше, это делается в JavaScriptthisПривязка определяется способом ее привязки, независимо от того, как работает React. Итак, давайте удалим код из самого React и создадим аналогичный пример на чистом JavaScript, который имитирует это поведение.
class Foo {
constructor(name){
this.name = name
}
display(){
console.log(this.name);
}
}
var foo = new Foo('Saurabh');
foo.display(); // Saurabh
//下面的赋值操作模拟了上下文的丢失。
//与实际在 React Component 中将处理程序作为 callback 参数传递相似。
var display = foo.display;
display(); // TypeError: this is undefined
Вместо имитации реальных событий и обработчиков мы заменяем их синонимичным кодом. Как мы видели в примере компонента React, контекст теряется из-за передачи обработчика в качестве обратного вызова, что приводит кthisзначение становитсяundefined. Это также то, что мы наблюдаем в этом чистом фрагменте кода JavaScript.
Вы можете спросить: «Подождите минутку!thisНе должно ли значение 's указывать на глобальный объект, потому что мы запускаем его в нестрогом режиме в соответствии с правилами привязки по умолчанию. "
ответ отрицательныйПричины следующие:
объявление классаа такжевыражение классапредметстрогий режимВыполнение, в основном включая конструкторы, статические методы и методы-прототипы. Функции получения и установки также выполняются в строгом режиме.
ты сможешьздесьПрочитайте статью полностью.
Итак, чтобы избежать ошибок, нам нужно выполнить привязку, как показано ниже.thisЗначение:
class Foo {
constructor(name){
this.name = name
this.display = this.display.bind(this);
}
display(){
console.log(this.name);
}
}
var foo = new Foo('Saurabh');
foo.display(); // Saurabh
var display = foo.display;
display(); // Saurabh
Мы можем сделать это не только в конструкторе, но и в другом месте. Учти это:
class Foo {
constructor(name){
this.name = name;
}
display(){
console.log(this.name);
}
}
var foo = new Foo('Saurabh');
foo.display = foo.display.bind(foo);
foo.display(); // Saurabh
var display = foo.display;
display(); // Saurabh
Но поскольку вся инициализация происходит в конструкторе, это лучшее место для написания связанного оператора события.
Почему нам не нужна привязка для стрелочных функций‘this’?
Внутри компонентов React у нас есть два других способа определения обработчиков событий.
class Foo extends React.Component{
handleClick = () => {
console.log(this);
}
render(){
return (
<button type="button" onClick={this.handleClick}>
Click Me
</button>
);
}
}
ReactDOM.render(
<Foo />,
document.getElementById("app")
);
class Foo extends React.Component{
handleClick(event){
console.log(this);
}
render(){
return (
<button type="button" onClick={(e) => this.handleClick(e)}>
Click Me
</button>
);
}
}
ReactDOM.render(
<Foo />,
document.getElementById("app")
);
Оба они используют стрелочные функции, представленные в ES6. При использовании этих альтернатив наш обработчик событий уже автоматически привязан к экземпляру компонента, и нам не нужно связывать его в конструкторе.
Причина в том, что в случае стрелочных функцийthisестьЛексическийпривязка. Это означает, что он может использовать окружающий контекст функции или глобальный контекст какthisценность .
В примере синтаксиса поля общедоступного класса стрелочная функция содержится вFooкласс или конструктор, поэтому его контекстом является экземпляр компонента, а это то, что нам нужно.
В случае стрелочных функций в качестве обратных вызовов, стрелочные функции содержатся вrender()метод, который вызывается React в контексте экземпляра компонента. Вот почему стрелочные функции также могут захватывать тот же контекст, и гдеthisЗначение будет правильно указывать на экземпляр компонента.
СвязанныйthisПодробнее о привязке см.этот отличный ресурс.
Суммировать
В компонентах класса React, когда мы передаем ссылку на обработчик событий в качестве обратного вызова, это выглядит так:
<button type="button" onClick={this.handleClick}>Click Me</button>
методы обработчика событий теряют своюнеявное связываниеконтекст. Когда событие запускается и вызывается обработчик,thisЗначение вернется кпривязка по умолчанию, то есть значение равноundefined, это связано с тем, что объявления классов и методы прототипов работают в строгом режиме.
Когда мы помещаем обработчик событийthisПри привязке к экземпляру компонента в конструкторе мы можем передать его как обратный вызов, не беспокоясь о потере его контекста.
Стрелочные функции исключены из этого поведения, потому что они используютЛексический this связывать, которые автоматически привязываются к контексту функции, в котором они определены.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.