2017-03-07 3 views
0

Ich habe ein Problem mit einer kleinen Anwendung für die Preisberechnung von einigen Produkten in React. Dies ist, wie meine Anwendung wie folgt aussieht:Reagieren JS - Kommunikation zwischen Kind und Eltern und doppelte Ereignisse

Image 1

Was ich jetzt brauche, ist eine globale Gesamt haben (Summe der Teilsumme der ListItem-Komponenten), aber ich weiß nicht, wie man das macht mit Reagieren. Ich habe versucht, die gleichen „onChange“ Ereignisse der kleinsten Komponente (ListItem) unter Verwendung ein Ereignis auf dem übergeordneten auslösen wie:

handleChange:function(event){ 

    this.props.onChange(event.target); 

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

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

aber auf diese Weise nur dieses Ereignis ausgelöst wurde und nicht den Zustand aktualisieren. Vermutlich vermisse ich etwas.

Was ich brauche ist, dass ich die Teilmenge, berechnet im ListItem, in der Elternkomponente, Table, übergebe, damit ich die globale Summe berechnen kann.

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

EDIT 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 
 
);

Antwort

0

Sie können eine Funktion im übergeordneten Element hinzufügen, die den Status dieser Komponente ändert, und diese Funktion dann als Prop an das untergeordnete Element senden.

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

+0

Ihre Lösung funktioniert teilweise, ich habe einige Anpassungen vorgenommen, hatte aber ein Leistungsproblem. Ich lege den neuen Code auf den Post, wenn Sie auschecken könnten. Danke –

0

Ich denke Redux für Sie gemacht wird.

Es hilft Ihnen, Eigenschaften zwischen Komponenten zu übergeben, die nicht unbedingt eine untergeordnete Beziehung haben. Im Grunde erstellt es einen globalen Status, auf den Sie von überall zugreifen können.

Es gibt eine Menge zu redux zu sagen (wir nennen es nicht react/redux ohne Grund), und dies ist ein Muss, wenn Sie etwas leistungsfähiges mit React machen wollen.

Weitere Informationen finden Sie in der Redux-Dokumentation!

0

Sie möchten Redux prüfen, wie Ksyqo erwähnt. Für solche Bedürfnisse ist es jedoch möglicherweise nicht ganz das, was Sie brauchen, da Sie in diesem Moment eine Vielzahl von Voreinstellungen und kognitiven Aufwand anwenden müssen, wenn Sie bereits einen bestehenden App-Code haben.

Für kleinere Projekt (e), könnte man feststellen, dass Sie können, mit besseren Ergebnissen, verwenden MobX Alternative, da es ein wenig einfacher zu implementieren vor allem in bestehenden Anwendungen ist. Es ist auch viel einfacher, darüber nachzudenken. Es wird ziemlich out of the box funktionieren, mit ein bisschen Magie beteiligt.

Was auch immer die Entscheidung, diese Kurve gilt für beide Redux und MobX wahr, und stellt das Problem der globalen Zustand vs Eltern-Kind gekettet Zustand (ehemals offensichtlich viel sauberer ist):

enter image description here

+0

MobX scheint ein guter Weg, dies zu tun. Ich habe versucht @ Joakim Tangnes Lösung und es hat funktioniert, aber es gibt Leistungsproblem, die Eingabeart wirklich langsam machen. –

Verwandte Themen