Реакция обратного вызова ребенка, связывающая это без переопределения оригинала this - PullRequest
0 голосов
/ 01 сентября 2018
class Parent extends React.Component {

  constructor(props) {
    super(props)
    this.handleChildOnClick = this.handleChildOnClick.bind(this)
  }

  handleChildOnClick() {
    /* I would like to do something here that requires both Child and Parent.
     * But 'this' points to Parent because I binded it in Parent's constructor.
     */
  }

  render() {
    return(
    <Child
      onClick={this.handleChildOnClick}
    />)
  }

}

В обратном вызове handleChildOnClick я хотел бы вызвать метод Child, чтобы получить некоторые данные и соответствующим образом обновить состояние Parent.

Если я связываю родительский элемент this с handleChildOnClick в конструкторе Parents, я теряю ссылку на Child, поэтому не могу вызвать метод Child. Но если я не связываю это, то я не могу установить состояние Родителя внутри handleChildOnClick.

Есть ли способ связать this, не переопределяя оригинал this?

Edit:
Мой дочерний компонент из библиотеки, поэтому я не могу его изменить.

Edit:
Я использую библиотеку response-google-maps . Дочерний компонент - GoogleMap , и я хотел бы сохранить новые границы просмотра GoogleMap в состоянии Родителя (вызывая getBounds() в GoogleMap) всякий раз, когда вызывается обратный вызов onBoundsChange GoogleMap.

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Желаемый this не считается Child контекстом. Функция передается как обратный вызов, она снабжена некоторым динамическим this. Если this является Child экземпляром компонента, это просто совпадение.

Проблема специфична для устаревших или плохо спроектированных библиотек, которые не охватывают современный JS OOP и полагаются на произвольную динамику this вместо передачи всех необходимых данных в качестве аргументов функции. Хорошо известный пример - библиотека D3.

Функция не может иметь два this. Популярный обходной путь - self = this трюк в сочетании с обычной (не стрелочной) функцией. Однако, это становится неуклюжим с синтаксисом класса, потому что это не может быть помещено снаружи constructor:

class Parent extends React.Component {
  constructor(props) {
    super(props)

    const self = this;
    this.handleChildOnClick = function handleChildOnClick() {
      // `self` is Parent instance
      // `this` is dynamic context
    };
  }

  render() {
    return(
    <Child
      onClick={this.handleChildOnClick}
    />)
  }
}

Эта перестановка неудобна, поскольку обычно ожидается, что this будет экземпляром класса в JS OOP.

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

function contextWrapper(fn) {
    const self = this;

    return function (...args) {
        return fn.call(self, this, ...args);
    }
}

class Parent extends React.Component {
  constructor(props) {
    super(props)

    this.handleChildOnClick = contextWrapper(this.handleChildOnClick.bind(this));
  }

  handleChildOnClick(context) {
      // `this` is Parent instance
      // `context` parameter is dynamic context
    }
  }

  render() {
    return(
    <Child
      onClick={this.handleChildOnClick}
    />)
  }
}
0 голосов
/ 01 сентября 2018

Вам необходимо вызвать обработчик в дочернем компоненте из его реквизита и обновить состояние родителя:

class Parent extends React.Component {

  handleChildOnClick = (data) => {
    /* I would like to do something here that requires both Child and Parent.
     * But 'this' points to Parent because I binded it in Parent's constructor.
     */
  }

  render() {
    return(
    <Child
      handleChildOnClick={this.handleChildOnClick}
    />)
  }

}

Тогда у вас дочерний компонент:

class Child extends React.Component {

      handleChildOnClick = () => {
        // you can even send data to parent click handler
        this.props.handleChildOnClick(data); // pass any arguments 
      }

      render() {
        return(
        <button
          onClick={this.handleChildOnClick}
        />)
      }

    }

Вот как это работает в привязке по реакции. Я надеюсь, что это будет полезно

...