Не удалось получить доступ к экземпляру React (this) внутри обработчика событий

Я пишу простой компонент в ES6 (с BabelJS), а функции this.setState не работают.

Типичные ошибки включают что-то вроде

Невозможно прочитать свойство 'setState' из undefined

или

this.setState не является функцией

Знаешь почему? Вот код:

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

Ответ 1

this.changeContent должен быть привязан к экземпляру компонента через this.changeContent.bind(this) перед передачей в качестве onChange prop, в противном случае переменная this в теле функции не будет ссылаться на экземпляр компонента, а на window. См. Функция:: привязка.

При использовании React.createClass вместо классов ES6 каждый метод, не связанный с жизненным циклом, определенный на компоненте, автоматически привязывается к экземпляру компонента. См. Autobinding.

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

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

против

render() {
  return <input onChange={this.changeContent.bind(this)} />;
}

Refs заданы на экземпляре компонента, а не на React.refs: вам нужно изменить React.refs.someref на this.refs.someref. Вам также необходимо привязать метод sendContent к экземпляру компонента, чтобы this ссылался на него.

Ответ 2

Морхаус прав, но это можно решить без bind.

Вы можете использовать функцию arrow вместе с предложением свойств класса:

class SomeClass extends React.Component {
  changeContent = (e) => {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return <input type="text" onChange={this.changeContent} />;
  }
}

Поскольку функция стрелки объявлена ​​в области конструктора, и поскольку функции стрелок поддерживают this из области объявления, все это работает. Недостатком здесь является то, что они не будут функциями на прототипе, все они будут воссозданы с каждым компонентом. Тем не менее, это не так много, так как bind приводит к тому же.

Ответ 3

Эта проблема является одной из первых вещей, которые испытывает большинство из нас при переходе от синтаксиса определения компонентов React.createClass() к классу ES6 класса расширения React.Component.

Это вызвано различиями контекста this в React.createClass() vs extends React.Component.

Использование React.createClass() будет автоматически связывать контекст (значения) this правильно, но это не так, если вы используете классы ES6. При использовании ES6 (расширение React.Component) контекст this по умолчанию равен null. Свойства этого класса автоматически не привязываются к экземпляру класса React (компонент).


Подходы к решению этой проблемы

Я знаю в общей сложности 4 общих подхода.

  • Связать свои функции в конструкторе класса. Многие считают, что это лучший подход, который позволяет вообще не прикасаться к JSX и не создает новую функцию для каждого повторного рендеринга компонентов.

    class SomeClass extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick}></button>
        );
      }
    }
    
  • Свяжите свои встроенные функции. Вы все еще можете найти этот подход, используемый здесь и там в некоторых учебниках/статьях/и т.д., Поэтому важно, чтобы вы знали об этом. Это та же концепция, что и # 1, но имейте в виду, что привязка функции создает новую функцию для каждого повторного рендеринга.

    class SomeClass extends React.Component {
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick.bind(this)}></button>
        );
      }
    }
    
  • Используйте функцию толстой стрелки. До тех пор, пока стрелки не будут функционировать, каждая новая функция определяет свое собственное значение this. Однако функция стрелок не создает свой собственный this контекст, поэтому this имеет исходное значение из экземпляра компонента React. Поэтому мы можем:

    class SomeClass extends React.Component {
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={ () => this.handleClick() }></button>
        );
      }
    }
    

    или

    class SomeClass extends React.Component {
      handleClick = () => {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick}></button>
        );
      }
    }
    
  • Использовать библиотеку функций функций для автоматической привязки ваших функций. Есть несколько библиотек утилиты, которые автоматически выполняют эту работу для вас. Вот некоторые из популярных, просто упомянуть несколько:

    • Autobind Decorator - это пакет NPM, который связывает методы класса с правильным экземпляром this, даже если методы отделяются. Пакет использует @autobind до того, как методы привяжут this к правильной ссылке к контексту компонента.

      import autobind from 'autobind-decorator';
      
      class SomeClass extends React.Component {
        @autobind
        handleClick() {
          console.log(this); // the React Component instance
        }
        render() {
          return (
            <button onClick={this.handleClick}></button>
          );
        }
      }
      

      Autobind Decorator достаточно умен, чтобы мы могли сразу связывать все методы внутри класса компонентов, как и подход № 1.

    • Класс Autobind - это еще один пакет NPM, который широко используется для решения этой проблемы привязки. В отличие от Autobind Decorator, он не использует шаблон декоратора, но на самом деле просто использует функцию внутри вашего конструктора, которая автоматически связывает методы Component с правильной ссылкой this.

      import autobind from 'class-autobind';
      
      class SomeClass extends React.Component {
        constructor() {
          autobind(this);
          // or if you want to bind only only select functions:
          // autobind(this, 'handleClick');
        }
        handleClick() {
          console.log(this); // the React Component instance
        }
        render() {
          return (
            <button onClick={this.handleClick}></button>
          );
        }
      }
      

      PS: Другая очень похожая библиотека React Autobind.


Рекомендация

Если бы я был вами, я бы придерживался подхода №1. Однако, как только вы получите тонну привязок в своем конструкторе классов, я бы рекомендовал вам изучить одну из вспомогательных библиотек, упомянутых в подходе # 4.


Другие

Это не связано с вашей проблемой, но вы не должны злоупотреблять ссылками.

В первую очередь вы можете использовать ссылки для "сделать вещи" в своем приложении. Если это так, найдите момент и более критически подумайте о том, где должно принадлежать государство в иерархии компонентов.

Для подобных целей, как и тот, который вам нужен, использование Component state. Таким образом, вы можете просто получить доступ к значению, подобному этому: this.state.inputContent.

Ответ 4

Хотя в предыдущих ответах был представлен общий обзор решений (например, привязка, функции стрелок, декораторы, которые делают это для вас), мне еще предстоит найти ответ, который на самом деле объясняет, почему это необходимо, что, на мой взгляд, является корнем путаницы и приводит к ненужным шагам, таким как ненужное переустройство и слепо следование за тем, что делают другие.

this динамично

Чтобы понять эту конкретную ситуацию, кратко расскажите, как this работает. Главное здесь - this привязка времени выполнения и зависит от текущего контекста выполнения. Следовательно, почему он обычно упоминается как "контекст" -общая информация о текущем контексте выполнения и почему вам нужно связывать, потому что вы теряете "контекст". Но позвольте мне проиллюстрировать проблему с помощью фрагмента:

const foobar = {
  bar: function () {
    return this.foo;
  },
  foo: 3,
};
console.log(foobar.bar()); // 3, all is good!

В этом примере мы получаем 3, как и ожидалось. Но возьмите этот пример:

const barFunc = foobar.bar;
console.log(barFunc()); // Uh oh, undefined!

Может быть неожиданно обнаружить, что он регистрируется неопределенно, - где же 3? Ответ лежит в "контексте", или как вы выполняете функцию. Сравните, как мы называем функции:

// Example 1
foobar.bar();
// Example 2
const barFunc = foobar.bar;
barFunc();

Обратите внимание на разницу. В первом примере мы точно определяем, где находится bar метод 1 - на объекте foobar:

foobar.bar();
^^^^^^

Но во втором мы храним метод в новой переменной и используем эту переменную для вызова метода без явного указания того, где этот метод существует, тем самым теряя контекст:

barFunc(); // Which object is this function coming from?

И в этом проблема, когда вы храните метод в переменной, теряется исходная информация о том, где находится этот метод (контекст, в котором выполняется этот метод). Без этой информации во время выполнения невозможно, чтобы интерпретатор JavaScript не смог связать правильный this без определенного контекста, this не работает должным образом 2.

Относительно реакции

Здесь приведен пример компонента React (сокращенный для краткости), страдающий от this проблемы:

handleClick() {
  this.setState(({ clicks }) => ({ // setState is async, use callback to access previous state
    clicks: clicks + 1, // increase by 1
  }));
}

render() {
  return (
    <button onClick={this.handleClick}>{this.state.clicks}</button>
  );
}

Но почему и как относится к предыдущему разделу? Это происходит потому, что они страдают от абстракции одной и той же проблемы. Если вы посмотрите, как React обрабатывает обработчики событий:

// Edited to fit answer, React performs other checks internally
// props is the current React component props, registrationName is the name of the event handle prop, i.e "onClick"
let listener = props[registrationName];
// Later, listener is called

Итак, когда вы делаете onClick={this.handleClick}, метод this.handleClick в конечном итоге назначается на listener переменных 3. Но теперь вы видите, что проблема возникает, поскольку мы назначили this.handleClick для listener, мы больше не указываем, где именно происходит handleClick ! С точки зрения listener - это просто некоторая функция, не привязанная к какому-либо объекту (или в данном случае экземпляру компонента React). Мы потеряли контекст, и поэтому интерпретатор не может вывести this значение для использования внутри handleClick.

Почему обязательные работы

Возможно, вам интересно, если интерпретатор решает this значение во время выполнения, почему я могу привязать обработчик так, чтобы он работал? Это связано с тем, что вы можете использовать Function#bind чтобы гарантировать this значение во время выполнения. Это делается путем установки внутреннего this привязки свойства на функции, что позволяет ему не выводить this:

this.handleClick = this.handleClick.bind(this);

Когда эта линия выполнена, предположительно, в конструкторе, ток this захватывается (РЕАКТ экземпляра компоненты) и установить в качестве внутреннего this связывания совершенно новой функции, возвращается из Function#bind. Это гарантирует, что при this вычисляется во время выполнения, интерпретатор не будет пытаться вывести что - либо, но использовать при условии, this значение, которое вы придан ему.

Почему свойства функции стрелки работают

Свойства класса функции Arrow в настоящее время работают через Babel на основе транспиляции:

handleClick = () => { /* Can use this just fine here */ }

становится:

constructor() {
  super();
  this.handleClick = () => {}
}

И это работает из-за того, что функции стрелки не связывают их с этим, но берут this из их охватывающей области. В этом случае constructor this, что указывает на React экземпляр, таким образом компонент дает вам правильно this. 4


1 Я использую "метод", чтобы ссылаться на функцию, которая должна быть привязана к объекту, и "функция" для тех, у кого нет.

2 Во втором фрагменте, не определено регистрируются вместо 3, потому что this по умолчанию глобального контексту исполнения (window, когда он не в строгом режиме, или еще undefined), когда она не может быть определена с помощью конкретного контекста. А в примере window.foo не существует, что дает неопределенный.

3 Если вы спуститесь в кроличью нору того, как выполняются события в очереди событий, invokeGuardedCallback.

4 Это на самом деле намного сложнее. React внутренне пытается использовать Function#apply на слушателях для собственного использования, но это не работает с функциями стрелок, поскольку они просто не связывают this. Это означает, что когда this внутри функции стрелки фактически оценивается, this разрешается каждой лексической средой каждого контекста выполнения текущего кода модуля. Контекст выполнения, который окончательно разрешает иметь this связывание, является конструктором, который имеет this указание на текущий экземпляр компонента React, что позволяет ему работать.

Ответ 5

Нам нужно связать функцию события с компонентом в конструкторе следующим образом:

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
    this.changeContent = this.changeContent.bind(this);
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

Спасибо

Ответ 6

Вы можете решить это тремя способами.

1. Заблокировать функцию события в самом конструкторе следующим образом:

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
    this.changeContent = this.changeContent.bind(this);
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

2.Bind, когда он называется

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent.bind(this)}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

3. Используя функции стрелок

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={()=>this.sendContent()}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

Ответ 7

Моя рекомендация - использование функций стрелок как свойств

class SomeClass extends React.Component {
  handleClick = () => {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}

и не используйте функции стрелок как

class SomeClass extends React.Component {
      handleClick(){
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={()=>{this.handleClick}}></button>
        );
      }
    }

потому что второй подход будет генерировать новую функцию для каждого вызова рендеринга, на самом деле это означает новую указатель новой версии реквизита, чем если бы вы позже позаботились о производительности, вы можете использовать React.PureComponent или в React.Component вы можете переопределить shouldComponentUpdate (nextProps, nextState) и неглубокой проверки при прибытии реквизитов

Ответ 8

Вы можете решить эту проблему следующим образом

Измените функцию sendContent на

 sendContent(e) {
    console.log('sending input content '+this.refs.someref.value)
  }

Изменить функцию рендеринга с помощью

<input type="text" ref="someref" value={this.state.inputContent} 
          onChange={(event)=>this.changeContent(event)} /> 
   <button onClick={(event)=>this.sendContent(event)}>Submit</button>

Ответ 9

Мы должны bind нашу функцию с this чтобы получить экземпляр функции в классе. Как и в примере

<button onClick={this.sendContent.bind(this)}>Submit</button>

Таким образом this.state будет действительным объектом.

Ответ 10

Эта проблема возникает, потому что this.changeContent и onClick={this.sendContent} не привязаны к этому экземпляра компонента.

Существует другое решение (в дополнение к use bind() в конструкторе()) для использования функций стрелок ES6, которые используют одну и ту же лексическую область окружающего кода и поддерживают этот, поэтому вы можете изменить свой код в render() следующим образом:

render() {
    return (

        <input type="text"
          onChange={ () => this.changeContent() } /> 

        <button onClick={ () => this.sendContent() }>Submit</button>

    )
  }

Ответ 11

Здравствуйте, если вы хотите не заботиться о привязке себя к вызову функции. Вы можете использовать "class-autobind" и импортировать его таким образом

import autobind from 'class-autobind';

class test extends Component {
  constructor(props){
  super(props);
  autobind(this);
}

Не записывайте autobind перед супервызовом, потому что он не будет работать

Ответ 12

Если вы хотите сохранить привязку в синтаксисе конструктора, вы можете использовать proposal-bind-operator и преобразовать свой код следующим образом:

constructor() {
  this.changeContent = ::this.changeContent;
}

Вместо:

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

гораздо проще, не нужно bind(this) или fatArrow.

Ответ 13

эта проблема возникает после реакции15.0, причем обработчик события не автоматически связывается с компонентом. поэтому вы должны привязать это к компоненту вручную всякий раз, когда вызывается обработчик событий.


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

// method 1: use a arrow function
    class ComponentA extends React.Component {
      eventHandler = () => {
        console.log(this)
      }
      render() {
        return ( 
        <ChildComponent onClick={this.eventHandler} /> 
        );
      }

// method 2: Bind your functions in the class constructor.
    class ComponentA extends React.Component {
      constructor(props) {
        super(props);
        this.eventHandler = this.eventHandler.bind(this);
      }
      render() {
        return ( 
        <ChildComponent onClick={this.eventHandler} /> 
        );
      }

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

Ответ 14

Вы используете ES6, поэтому функции не будут автоматически связываться с "этим" контекстом. Вы должны вручную привязать функцию к контексту.

constructor(props) {
  super(props);
  this.changeContent = this.changeContent.bind(this);
}

Ответ 15

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

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

this.sendContent = this.sendContent.bind(this)

В ES6 используйте функции стрелок

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

sendContent = (event) => {

}

Ответ 16

Александр Кирзенберг прав, но еще одна важная вещь, на которую нужно обратить внимание, - это то, где вы ставите свою привязку. Я застрял в ситуации в течение нескольких дней (возможно, потому, что я новичок), но в отличие от других, я знал о bind (который я уже применял), поэтому я просто не мог понять, почему у меня все еще есть эти ошибки. Оказывается, у меня была привязка в неправильном порядке.

Другим также является тот факт, что я вызывал функцию в "this.state", которая не знала о связывании, потому что она оказалась выше строки привязки,

Ниже было то, что у меня было (кстати, это моя первая публикация, но я думал, что это очень важно, поскольку я не мог найти решение где-нибудь еще):

constructor(props){
    super(props);

       productArray=//some array

    this.state={ 
        // Create an Array  which will hold components to be displayed
        proListing:productArray.map(product=>{return(<ProRow dele={this.this.popRow()} prodName={product.name} prodPrice={product.price}/>)})
    }

    this.popRow=this.popRow.bind(this);//This was the Issue, This line //should be kept above "this.state"

Ответ 17

Решение:

  1. Без явного связывания, bind с именем метода, вы можете использовать синтаксис жирных стрелочных функций () => {}, который поддерживает контекст this.
import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      inputContent: 'startValue'
    }
  }

  sendContent = (e) => {
    console.log('sending input content ',this.state.inputContent);
  }

  changeContent = (e) => {
    this.setState({inputContent: e.target.value},()=>{
      console.log('STATE:',this.state);
    })
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" value={this.state.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

Другие решения:

  1. Свяжите свои функции в конструкторе класса.

  2. Свяжите свои функции в шаблоне JSX, избегая скобок {} {this.methodName.bind(this)}

Ответ 18

вот похожая проблема. Невозможно сослаться на "это" из обратных вызовов. Не могли бы вы объяснить это или указать мне соответствующее предварительное объяснение

import React, { Component } from 'react';

class SearchDevice extends Component {
    constructor(props) {
        super(props); //React props are immutable
        this.state = {//React state is mutable
            deviceName: '',
            devices: []
        };

        // This binding is necessary to make 'this' work in the callback
        this.handleChange = this.handleChange.bind(this);
        this.handleSearchDevice = this.handleSearchDevice.bind(this);
    }

    componentWillMount() {
        this.setState({
            devices: this.props.devices
        });
    }

    componentDidMount() {
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            devices: nextProps.devices
        });
    }

    handleChange(event) {
        this.setState({deviceName: event.target.value });
    }
    handleSearchDevice(event) {
        console.log('Searching '+this.state.deviceName)
        event.preventDefault();

        //Get data from API
        const url = 'device/name'
        const data = { deviceName:this.state.deviceName}
        fetch(url, { method: 'POST', // or ‘PUT
            body: JSON.stringify(data), // data can be 'string' or {object}!
            headers:{ 'Content-Type': 'application/json' }
        }).then(res => {
            res.json().then(function(data) {
                console.log('API Response: '+JSON.stringify(data))
                try {
                    this.setState({devices: data.resp, deviceName: data.deviceName})
                } catch(err) {
                    console.log('catch ' + err.stack)
                    this.callback1(data)
                }
            });
        }).catch(error => {
            console.error('Error:', error)
        }).then(response => {
            console.log('Success:', response)
        });
    }
    callback1(data) {
        this.setState({devices: data.resp, deviceName: data.deviceName})
        console.log(data)
    }

    render() {
        return (
            <div className="container-fluid" id="respContent">
                <form onSubmit={this.handleSearchDevice}>
                    <input type="hidden" id="deviceId" name="deviceId" value={this.state.deviceId} />
                    <label htmlFor="deviceName">Device Name</label>
                    <input type="text" className="form-control" id="deviceName" value={this.state.deviceName} onChange={this.handleChange} />
                    <input type="submit" value="Search" />
                </form>

                <div style={{height:"500px", overflow: "auto", border: "1px solid gray"}}>
                    {this.state.devices}
                </div>
            </div>
        );
    }

    componentDidUpdate(prevProps) {
    }

}
export default SearchDevice;


import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from './Home';
import SearchDevice from './SearchDevice';
import SearchTerminal from './SearchTerminal';
import InvalidRequest from './InvalidRequest';

class Routes extends Component {
  render() {
    return (
      <Switch>
        <Route exact path='/' component={Home}></Route>
        <Route path='/search' component={SearchDevice}></Route>
        <Route path='/terminal' component={SearchTerminal}></Route>
        <Route path='/*' component={InvalidRequest}></Route>
      </Switch>
    );
  }
}
export default Routes;
'''[enter image description here][1]


  [1]: https://i.stack.imgur.com/WoRxu.jpg

Ответ 19

bind(this) может решить эту проблему, и в настоящее время мы можем использовать еще 2 способа для достижения этой цели, если вам не нравится использовать bind.

1) Традиционным способом мы можем использовать bind(this) в конструкторе, так что когда мы используем функцию в качестве обратного вызова JSX, контекстом this является сам класс.

class App1 extends React.Component {
  constructor(props) {
    super(props);
    // If we comment out the following line,
    // we will get run time error said 'this' is undefined.
    this.changeColor = this.changeColor.bind(this);
  }

  changeColor(e) {
    e.currentTarget.style.backgroundColor = "#00FF00";
    console.log(this.props);
  }

  render() {
    return (
      <div>
        <button onClick={this.changeColor}> button</button>
      </div>
    );
  }
}

2) Если мы определяем функцию как атрибут/поле класса с помощью функции стрелки, нам больше не нужно использовать bind(this).

class App2 extends React.Component {
  changeColor = e => {
    e.currentTarget.style.backgroundColor = "#00FF00";
    console.log(this.props);
  };
  render() {
    return (
      <div>
        <button onClick={this.changeColor}> button 1</button>
      </div>
    );
  }
}

3) Если мы используем функцию стрелки в качестве обратного вызова JSX, нам также не нужно использовать bind(this). И еще больше, мы можем передать параметры. Выглядит хорошо, не правда ли? но его недостатком является проблема производительности, подробности см. в документе ReactJS.

class App3 extends React.Component {
  changeColor(e, colorHex) {
    e.currentTarget.style.backgroundColor = colorHex;
    console.log(this.props);
  }
  render() {
    return (
      <div>
        <button onClick={e => this.changeColor(e, "#ff0000")}> button 1</button>
      </div>
    );
  }
}

И я создал Codepen для демонстрации этих фрагментов кода, надеюсь, это поможет.