React——给dangerouslySetInnerHTML子元素添加一个点击监听器

Mir*_*318 3 reactjs

我有这个 html 文本:

"<span id='capo' class='capo' data-capo=3>Capo 3</span>"
Run Code Online (Sandbox Code Playgroud)

这是通过插入的较大 html 的一部分 dangerouslySetInnerHTML

我有一个这样的听众:

componentDidMount() {
  document.getElementById('capo').addEventListener('click', this.changeKey);
}
Run Code Online (Sandbox Code Playgroud)

然而,这只适用于一键点击——之后侦听器不存在。我猜是因为 React 已经替换了组件(因为我更改了 中的状态this.changeKey),因此侦听器不再存在。

如何可靠地为 React 组件设置侦听器?

sla*_*iej 5

在这种情况下,您可以使用事件冒泡!

只需将您的事件侦听器添加到上层元素(有的dangerouslySetInnerHTML就可以了)侦听点击并确保它e.target.id等于所需的元素 ID。

查看下面的示例(它dangerouslySetInnerHTML仅用于展示事件冒泡的工作原理以及如何将其与 React 一起使用,您不应该在现实生活中编写这样的组件):

class Element extends React.Component {
  state = {
    loadTime: 0,
    lastUpdate: 0
  };
  
  lastUpdateTimer = null;

  componentDidMount() {
    this.resetTimer();
    
    this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
    
    this.dynamicContentElement.addEventListener("click", this.handleClick)
  }
  
  componentWillUnmount() {
    clearInterval(this.lastUpdateTimer);
    this.dynamicContentElement.removeEventListener(this.handleClick)
  }
  
  resetTimer() {
    const now = Date.now();

    this.setState({
      loadTime: now,
      lastUpdate: now
    });
  }
  
  setLastUpdate = () => {
    this.setState({
      lastUpdate: Date.now()
    });
  }

  getDynamicContent() {
    const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
    return {
      __html: `<p>
        You are here: <strong>${time}</strong> seconods.
        <br>
        <button id="btn">Click to reset counter</button>
       </p>`
    };
  }
  
  handleClick = (e) => {
    if (e.target.id === "btn") {
      this.resetTimer();
    }
  }

  render() {
    return (
      <div>
        Dynamic content below:
        <div
          ref={el => this.dynamicContentElement = el}
          dangerouslySetInnerHTML={this.getDynamicContent()}
        />
      </div>
    );
  }
}


ReactDOM.render(
  <Element />,
  document.getElementById('root')
);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)