【问题标题】:React child callback binding this without overriding the original this反应子回调绑定 this 而不覆盖原始 this
【发布时间】:2018-09-01 07:36:54
【问题描述】:
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 的状态。

如果我在 Parent 构造函数中将 Parent 的 this 绑定到 handleChildOnClick,那么我失去了对 Child 的引用,因此无法调用 Child 的方法。但是如果我不绑定它,那么我将无法在handleChildOnClick 中设置 Parent 的状态。

有没有办法绑定this而不覆盖原来的this

编辑:
我的子组件来自一个库,所以我无法修改它。

编辑:
我正在使用react-google-maps 库。子组件是GoogleMap,每当GoogleMap 的onBoundsChange 回调被触发时,我想将GoogleMap 的新视图边界存储在父状态(通过在GoogleMap 上调用getBounds())。

【问题讨论】:

  • 最好写下你的handleChildOnClick(),这将有助于找出你的问题。

标签: javascript reactjs this


【解决方案1】:

所需的this 不被视为Child 上下文。该函数作为回调传递,它提供了一些动态的this。如果thisChild 组件实例,那只是巧合。

该问题特定于遗留或设计不佳的库,这些库不包含现代 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 中的类实例。

this related answer 中所述,解决此问题的一种方法是提供辅助函数,该函数在内部执行此技巧并将动态上下文映射到函数参数:

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}
    />)
  }
}

【讨论】:

  • 最终我在子组件中添加了一个ref。感谢您提供另一种方法来处理此问题。
  • 不客气。是的,如果 this 是专门的 Child 实例,则 ref 将起作用。我没有检查库是如何工作的,但在常规点击处理程序中,第一个参数包含所有必要的数据,这也可能是这种情况。您可以检查处理程序接收哪些参数。
【解决方案2】:

您需要从子组件的 props 中调用处理程序并更新父组件的状态:

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}
        />)
      }

    }

这就是它在 react 的 pne 方式绑定中的工作方式。 我希望这会有所帮助

【讨论】:

  • 感谢您的解决方案。但是子组件来自一个库,所以我不能在它上面定义新函数。有没有不需要修改 Child 的解决方案?
  • 那你为什么需要两个处理程序呢?您可以处理子处理程序,并且您已经在父组件中声明了 Child
  • 您能否在您的帖子中更简短地说明您正在使用什么库
猜你喜欢
  • 2018-06-03
  • 2018-01-02
  • 2019-05-07
  • 2020-01-15
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多