【问题标题】:React JS - Communication between Child and Parent and double eventsReact JS - Child和Parent之间的通信以及双重事件
【发布时间】:2025-12-12 01:25:01
【问题描述】:

我在制作一个小应用程序时遇到了问题 用于 React 中某些产品的价格计算。这是我的应用程序的样子:

我现在需要的是有一个全局总数(ListItem 组件的部分总数的总和),但我不知道如何使用 React 来做到这一点。我尝试使用最小组件(ListItem)的相同“onChange”事件来触发父级事件,例如:

handleChange:function(event){

  this.props.onChange(event.target);

  const target = event.target;
  const name = target.name;
  const value = target.value;

  this.setState({
    [name]: value
  });
},

但是通过这种方式,只有这个事件被触发并且没有更新状态。 可能我错过了一些东西。

回顾一下我需要的是传递在ListItem中计算的部分总计,在父组件Table中,以便我可以计算全局总计。

function Header(){
  return (
    <h1>Calcolo costo prodotti</h1>
  )
}

var ListItem = React.createClass({
    getInitialState: function(){
      return {name: this.props.value.product.name, costo: this.props.value.product.costo, quantita: this.props.value.product.quantita, totale: 0} 
    },
  
    render: function(){
    return(
      <tr>
        <td><input type="text" name="name" value={this.state.name} onChange={this.handleChange} placeholder="Nome..."/></td>
        <td><input type="text" name="costo" value={this.state.costo} onChange={this.handleChange} placeholder="Costo unitario..."/></td>
        <td><input type="text" name="quantita" value={this.state.quantita} onChange={this.handleChange} placeholder="Quantità..."/></td>
        <td className="total">{this.calcoloTotale()}</td>
      </tr>
    )
  },
    
  handleChange:function(event){
    const target = event.target;
    const name = target.name;
    const value = target.value;
    
    this.setState({
      [name]: value
    });
  },
  
  calcoloTotale: function(){
    var Ltotale = this.state.costo * this.state.quantita;
    this.setState({totale: Ltotale});
    return Ltotale;
  }
});
  
  
var Table = React.createClass({
  getInitialState: function(){
    return { totale: 0 }
  },
  
  render: function(){
    return(
      <div>
        <table>
          <tr>
            <th>Nome</th>
            <th>Prezzo</th> 
            <th>Quantità</th>
            <th>Totale</th>
          </tr>
          {this.props.items.map((prodotto) =>
            <ListItem key={prodotto.id} value={prodotto}/>
          )}
        </table>
      </div>
    )
  }
});

var AddNewRow = React.createClass({
  render: function(){
    return(
      <div>
        <button onClick={this.props.onClick}>+</button>
        Aggiungi prodotto
      </div>
    )
  }
});

var Calculator = React.createClass({
  getInitialState: function(){
    return {
      counter: 2, lists: [{id: "0", product: {name: "Esempio 1",costo: "25",quantita: "3"}}, {id: "1", product: {name: "Esempio 2",costo: "32",quantita: "4"}}]
    }
  },
  
  render: function(){
    return (
      <div className="container">
        <Header />
        <Table items={this.state.lists} ids={this.counter}/>
        <AddNewRow onClick={this.addRow}/>
      </div>
    )
  },
  
  addRow: function(){
    this.setState({counter: this.state.counter + 1});
    var listItem = {id: this.state.counter, product:{name:"", costo: "", quantita: ""}};
    var allItem = this.state.lists.concat([listItem])
    this.setState({lists: allItem});
  }
});

ReactDOM.render(
  <Calculator />,
  document.body
);

编辑 1:

var totalVec = new Array();

function Header(){
  return (
    <h1>Calcolo costo prodotti</h1>
  )
}

var ListItem = React.createClass({
    getInitialState: function(){
      return {name: this.props.value.product.name, costo: this.props.value.product.costo, quantita: this.props.value.product.quantita} 
    },
  
    render: function(){
    return(
      <tr>
        <td><input type="text" name="name" value={this.state.name} onChange={this.handleChange} placeholder="Nome..."/></td>
        <td><input type="text" name="costo" value={this.state.costo} onChange={this.handleChange} placeholder="Costo unitario..."/></td>
        <td><input type="text" name="quantita" value={this.state.quantita} onChange={this.handleChange} placeholder="Quantità..."/></td>
        <td className="total">{this.calcoloTotale()}</td>
      </tr>
    )
  },
    
  handleChange:function(event){
    const target = event.target;
    const name = target.name;
    const value = target.value;
    
    this.setState({
      [name]: value
    });
    
    this.props.updateGlobalTotal();
  },
  
  calcoloTotale: function(){
    var Ltotale = this.state.costo * this.state.quantita;
    totalVec[this.props.value.id] = Ltotale;
    return Ltotale;
  }
});
  
  
var Table = React.createClass({
  getInitialState: function(){
    return { totale: 0 } 
  },
  
  render: function(){
    return(
      <div>
        <table>
          <tr>
            <th>Nome</th>
            <th>Prezzo</th> 
            <th>Quantità</th>
            <th>Totale</th>
          </tr>
          {this.props.items.map((prodotto) =>
            <ListItem key={prodotto.id} value={prodotto} updateGlobalTotal={this.updateGlobalTotal}/>
          )}
        </table>
        <h1>{this.state.totale}</h1>
      </div>
    )
  },
  
  componentDidMount: function(){
    var total = 0;
    for(var i = 0; i < this.props.ids; i++){
      total += totalVec[i];
    }
    
    this.setState({totale: total});
  },
  
  updateGlobalTotal: function(){
    var total = 0;
    for(var i = 0; i < this.props.ids; i++){
      total += totalVec[i];
    }
    
    this.setState({totale: total});
  }
  
});

var AddNewRow = React.createClass({
  render: function(){
    return(
      <div>
        <button onClick={this.props.onClick}>+</button>
        Aggiungi prodotto
      </div>
    )
  }
});

var Calculator = React.createClass({
  getInitialState: function(){
    return {
      counter: 2, lists: [{id: "0", product: {name: "Esempio 1",costo: "25",quantita: "3"}}, {id: "1", product: {name: "Esempio 2",costo: "32",quantita: "4"}}]
    }
  },
  
  render: function(){
    return (
      <div className="container">
        <Header />
        <Table items={this.state.lists} ids={this.state.counter}/>
        <AddNewRow onClick={this.addRow}/>
      </div>
    )
  },
  
  addRow: function(){
    this.setState({counter: this.state.counter + 1});
    var listItem = {id: this.state.counter, product:{name:"", costo: "", quantita: ""}};
    var allItem = this.state.lists.concat([listItem])
    this.setState({lists: allItem});
  }
});

ReactDOM.render(
  <Calculator />,
  document.body
);

【问题讨论】:

    标签: javascript reactjs html-table dynamic-tables


    【解决方案1】:

    你可能想看看 Ksyqo 提到的 Redux。但是,对于此类需求,它可能并不完全是您所需要的,因为当您已经编写了现有的应用程序代码时,它会要求您在这个特定时刻应用各种样板和认知开销。

    对于较小的项目,您可能会发现您可以使用 MobX 替代方案,因为它更容易实现,尤其是在现有应用程序中。推理起来也容易得多。它几乎可以开箱即用,并涉及一些魔法。

    无论决定是什么,这张图对 Redux 和 MobX 都适用,并说明了 全局状态父子链式状态 的问题(前者显然是更干净):

    【讨论】:

    • MobX 似乎是一个很好的方法。我已经尝试过@Joakim Tangnes 解决方案,它确实有效,但存在性能问题,导致输入类型非常慢。
    【解决方案2】:

    您可以在父级中添加一个更改该组件状态的函数,然后将该函数作为道具发送给子级。

    var ListItem = React.createClass({
        getInitialState: function(){
          return {name: this.props.value.product.name, costo: this.props.value.product.costo, quantita: this.props.value.product.quantita, totale: 0} 
        },
        
      ...
      
      calcoloTotale: function(){
        var Ltotale = this.state.costo * this.state.quantita;
        this.props.updateGlobalTotal(Ltotale);
        this.setState({totale: Ltotale});
        return Ltotale;
      }
    });
      
      
    var Table = React.createClass({
      getInitialState: function(){
        return { totale: 0 }
      },
      updateGlobalTotal: function(value){
          this.setState({totale: this.state.totale + value})
      }
      
      render: function(){
        return(
          <div>
            <table>
              <tr>
                <th>Nome</th>
                <th>Prezzo</th> 
                <th>Quantità</th>
                <th>Totale</th>
              </tr>
              {this.props.items.map((prodotto) =>
                <ListItem key={prodotto.id} value={prodotto} updateGlobalTotal={this.updateGlobalTotal}/>
              )}
            </table>
          </div>
        )
      }
    });

    【讨论】:

    • 您的解决方案部分有效,我做了一些调整,但出现了性能问题。如果您可以签出,我会将新代码放在帖子上。谢谢
    【解决方案3】:

    我认为Redux 是为你而设的。

    它可以帮助您在不一定具有子/父关系的组件之间传递属性。基本上,它创建了一个您可以从任何地方访问的全局状态。

    关于 redux 有很多话要说(我们不会无缘无故地称之为 react/redux),如果你想用 React 做一些强大的事情,这是必须的。

    您可以在 Redux 文档中找到更多信息!

    【讨论】: