Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.js How to Pass Event Up Through Multiple Child Components?

Tags:

reactjs

I have a react.js app with structure like this:

<CalcApp /> --- root component, state is set here
  <CalcTable /> --- 1st child component
    <CalcRow /> --- 2nd child component
      - input onChange event

I want to be able to listen to an an onChange event happening inside the <-CalcRow-> component, but I am having trouble passing the event all the way up to the root component.

I have looked around the web, and stackoverflow, pretty extensively, but have not found examples of how to do this.

What is the best way to pass the event from a deeply nested child component all the way back up to the root component so that I can change state?

Here is my complete code:

var React = window.React = require('react'),
// include external components from ui folder like the exmaple blow: 
//  Timer = require("./ui/Timer"),
    Timer = require("./ui/Timer"),
    mountNode = document.getElementById("app");

var catOne =  [
    {name  : 'one', value : 5, key : 1},
    {name  : 'two', value : 2, key : 2},
    {name  : 'three', value : 3, key : 3}
      ]; 

var CalcTable = React.createClass({
  changeHandler: function(){
    console.log('ding');
    this.props.onChange();
  },
  render: function() {
    var rows = [];

    // var myVar = this.props.cat1;     

    this.props.cat1.forEach(function(item){
      rows.push(<CalcRow item={item} ref="row" key={item.key}  onChange={this.changeHandler} />);
    });
    return(
      <table>{rows}</table>
    )
  }
});

var CalcRow = React.createClass({
    changeHandler: function(e) {
      console.log('ping');
        this.props.onChange();
    },
  render: function(){
    return(
        <tr>
          <td>h</td>
          <td>{this.props.item.name}</td>
          <td><input  cat1={this.props.item} value={this.props.item.value} name={this.props.item.key}  onChange={this.changeHandler}  /></td>
        </tr>
      )
  }
});

var AddRowButton = React.createClass({ 
     handleSubmit: function(e) {
      e.preventDefault();
      this.props.onSubmit(this);
  },
  render: function(){
    return(
        <form onSubmit={this.handleSubmit}>
          <input />
          <button>Add</button>
        </form>
      )
  }
});

var SectionSummary = React.createClass({
  render: function(){
  return(
    <div className="summary">
        <div className="table-summary">
        stuff
        </div>

    </div>
    );
  }
});

var CalcApp = React.createClass({
      changeHandler: function(e) {
      console.log('bong');
    },
    getInitialState: function(){
    return {
      cat1: this.props.cat1
      };
     },
    handleSubmit: function() {
        // console.log(this.props.cat1);
        // console.log(this.props.cat1.length+1);
        var newKeyVal = this.props.cat1.length+1;
        c = this.props.cat1; 
        c = c.push({name : "four", value : 4, key : newKeyVal});
        this.setState({
        cat1:c
      });
        // console.log(this.state.cat1);
    },
  render: function() {
    return (
      <div>
          <h3>title</h3>
          <CalcTable  cat1={this.props.cat1} onChange={this.changeHandler}/>
         <div className="stuff"><p>stuff</p></div>
         <div className="stuff">
            <AddRowButton cat1={this.props.cat1} onSubmit={this.handleSubmit}/>
          </div>
            <SectionSummary />
      </div>
    );
  }
});

React.render(<CalcApp cat1={catOne}/>, mountNode);
like image 410
psvj Avatar asked May 24 '15 06:05

psvj


People also ask

How do you pass data between two child components in React?

First, you'll need to create two components, one parent and one child. Next, you'll import the child component in the parent component and return it. Then you'll create a function and a button to trigger that function. Also, you'll create a state using the useState Hook to manage the data.

How do you pass data between sibling components in react JS?

To move data from a component to a sibling component, the simplest way is to pass a function from the parent component as a prop (i.e. "prop function") to its child that wants to update the data.

Can we use same event handlers on multiple components?

Answer. By passing an anonymous function, or a named function, with multiple event handler calls as the function body, to our event listener (like onClick , onKeyUp , onChange , etc) we can call multiple event handlers in response to a single event.


3 Answers

Just a word of caution when using pub/sub: It's too easy to go overboard with events. At first, it seems to solve all problems you've ever had. Then after a while you notice that all of your code is a tangled ball of event-spaghetti.

Events are a bit like globals in that they tend to make everything better until they make everything worse. And when you end up where they make everything worse, it's hard to go back unfortunately.

So use events sparsely. Prefer passing down functions to child components so that child components can notify parents. That too is a sort of event, but more isolated and easier to follow.

You might think "Well what about Flux, that is all about events?". And it sure it, but has quite a rigid structure for how and when to send events which makes it easier to manage.

like image 97
Anders Ekdahl Avatar answered Oct 06 '22 19:10

Anders Ekdahl


One solution can be to use a common event dispatcher.

In your parent component, you would write

var dispatcher = require('./my-dispatcher')
dispatcher.on('my.event', function (e, myArg) {
  // do some stuff here
})

and in the child

var dispatcher = require('./my-dispatcher')
dispatcher.trigger('my.event', 'my arg value')

If you do not want to implement the dispatcher yourself, there are some libraries around. I have not tried it, but for example https://github.com/mrdoob/eventdispatcher.js/ seems to do this job.

like image 43
Daniel Perez Avatar answered Oct 06 '22 19:10

Daniel Perez


I use PubSubJS to communicate between my React components... that way you keep everything independent of each other and loosely coupled.

You can read more about PubSubJS here: https://github.com/mroderick/PubSubJS

To communicate, one component publish and any subscriber will get the data.

I learned about this from this blog: http://maketea.co.uk/2014/03/05/building-robust-web-apps-with-react-part-1.html#component-communication

He is using window.addEventListener but I don't recommend it since not all browser supports it, plus the PubSubJS is much easier to implement.

like image 27
Rosdi Kasim Avatar answered Oct 06 '22 19:10

Rosdi Kasim