React: событие, пузырящееся через вложенные компоненты

Скажем, у меня есть вложенные компоненты вроде этого:

<root />
  <comp1 />
    <comp2 />
      <target id={this.props.id}>
        <div>click me</div>

Я хочу, чтобы щелчок на целевой странице выполнял функцию root:

//on root component
this.action = function(id){}

Нужно ли вручную задавать свойство для каждого компонента в цепочке, например, в примере с руководством React? Jsfiddle

<root />
  <comp1 clickHandler={this.action}/>
    <comp2 clickHandler={this.clickHandler}/>
      <target id={this.props.id} clickHandler={this.clickHandler} />
        <div onClick={this.props.clickHandler.bind(this, this.props.id)}>click me</div>

Или есть способ, чтобы пузырить события вверх, как в обычном DOM?

Ответ 1

Вы можете использовать стенографию, чтобы передать реквизиты дочерним компонентам

<Component {...this.props} more="values" />

Перенос реквизита

Итак, в вашем случае:

<root />
  <comp1 clickHandler={this.action}/>
    <comp2 {...this.props} />
      <target {...this.props} id={this.props.id} />
        <div onClick={this.props.clickHandler.bind(this, this.props.id)}>click me</div>

Ответ 2

React поддерживает Synthetic Events через него Virtual DOM как на этапах захвата, так и в пузырьках (как описано здесь: https://facebook.github.io/react/docs/events.html).

Это означает, что вы можете поместить обработчик onClick на любой элемент DOM рядом с корнем, и он должен запускать для всех событий Click на странице:

<root>
  <div onClick={this.handleAllClickEvents}>
    <comp1>
      <comp2>
        <target>
          <div id={this.props.id}>click me</div>

Однако, поскольку он будет срабатывать для всех событий кликов, вам нужно будет устранить двусмысленность между ними в обработчике кликов (что делает некоторый довольно уродливый код).

function handleAllClickEvents(event) {
  var target = event.relatedTarget;
  var targetId = target.id;
  switch(targetId) {
    case 'myBtn1':
      // handle myBtn1 click event
    case 'myBtn2':
      // handle myBtn2 click event
  }
}

Этот стиль делегирования событий на самом деле является тем, что React делает под капотом (https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#under-the-hood-autobinding-and-event-delegation), поэтому вы должны спросить себя, что именно вы действительно хотите сделать.

В качестве альтернативы вы можете посмотреть что-то вроде шаблона Dispatcher в Flux (https://facebook.github.io/flux/docs/actions-and-the-dispatcher.html#content). Это немного сложнее, но это лучшее решение в целом.