34

Let's say I have nested components like this:

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

I want to make clicking on target run a function on root:

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

Do I need to do manually set a property on every component in the chain, like in the React tutorial example? 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>

Or is there some way to bubble the events up like in normal DOM?

1

3 Answers 3

39

React supports Synthetic Events across it's Virtual DOM in both capturing and bubbling phases (as described here: https://facebook.github.io/react/docs/events.html).

This means that you could put an onClick handler on any DOM element near the root and it should trigger for all Click events on the page:

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

However, since it will fire for all click events, you would need to disambiguate between them in the click handler (which makes for some pretty ugly code).

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

This style of Event Delegation is actually what React does under the hood (https://shripadk.github.io/react/docs/interactivity-and-dynamic-uis.html#under-the-hood-autobinding-and-event-delegation) so you have to ask yourself if that's what you really want to do.

Alternatively you might want to look at something like the Dispatcher pattern in Flux (https://reactjs.org/blog/2014/07/30/flux-actions-and-the-dispatcher.html). It's a little bit more complicated to get going but it's a better solution overall.

Sign up to request clarification or add additional context in comments.

3 Comments

I thought you aren't supposed to mutate props?
«for all Click events on the page» It more corect to say, for all descendants (inner nodes).
facebook.github.io/flux/docs/… <-- this link does not work.
4

You can use the shorthand to pass props through to child components

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

Transferring props

So in your case:

<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>

5 Comments

While {...this.props} works, it makes it really difficult to reason about what's get passed down components, after maintaining a project with hundreds of components this get dizzyingly impossible to track.
@Patrick you can try Redux. It introduce a concept selector, which allow you select the props from a global data store instead of passing props from parent
Thx, redux is used for global state, plus its not what the question eas about. I just specifically stated that the spread operator is confusing at best when things get nested
I have not used react very long so take this with a grain of salt but this seems like an anti-pattern to me if you're trying to decouple your components and reuse them. This pattern makes them dependent upon being children of the parent object with specifically named properties.
This is smelly, today it has a name - prop drilling, and it is an anti pattern
1

If you want to distinguish which element was clicked at the end, you may use Event object and find there some interesting stuff, such as DOM element type.

<AnElement>
 <button onClick={e => this.eventHandler(e)}>Click me</button>
 <input type="text" onClick={e => this.eventHandler(e)}>Click me</input>

eventHandler = (e) => {
        console.log(e, e.nativeEvent.toElement.nodeName);
...}

And you get button or input depending on what you've clicked. That's what i looked for for my project.

More over you may find a DOM tree in an array representation array representation

Hope it helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.