React.js如何通过多个子组件传递事件?

psv*_*svj 10 reactjs

我有一个react.js应用程序,结构如下:

<CalcApp /> --- root component, state is set here
  <CalcTable /> --- 1st child component
    <CalcRow /> --- 2nd child component
      - input onChange event
Run Code Online (Sandbox Code Playgroud)

我希望能够听到<-CalcRow->组件内发生的onChange事件,但是我无法将事件一直传递到根组件.

我已经浏览了网络和stackoverflow,相当广泛,但还没有找到如何执行此操作的示例.

将事件从深度嵌套的子组件一直传递回根组件以便我可以更改状态的最佳方法是什么?

这是我的完整代码:

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);
Run Code Online (Sandbox Code Playgroud)

And*_*ahl 5

使用pub/sub时要小心谨慎:过于容易过度使用事件.起初,它似乎解决了你曾经遇到的所有问题.过了一会儿,你会注意到你的所有代码都是事件意乱的纠结球.

事件有点像全局变量,因为它们会让一切变得更好,直到它们变得更糟.当你最终让一切变得更糟时,不幸的是很难回去.

所以稀疏地使用事件.首选将函数传递给子组件,以便子组件可以通知父组件.这也是一种事件,但更加孤立,更容易遵循.

您可能会想"那么关于Flux,那就是关于事件的事情?".它确实如此,但对于如何以及何时发送事件具有相当严格的结构,这使得它更易于管理.


Dan*_*rez 1

一种解决方案是使用通用事件调度程序。

在你的父组件中,你可以写

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

并在孩子身上

var dispatcher = require('./my-dispatcher')
dispatcher.trigger('my.event', 'my arg value')
Run Code Online (Sandbox Code Playgroud)

如果您不想自己实现调度程序,可以使用一些库。我还没有尝试过,但例如https://github.com/mrdoob/eventdispatcher.js/似乎可以完成这项工作。