What is the best way to handle state changes in a deep node which also need to be handled by a parent node. Here is my situation:
<Table>
<Row prop={user1}>
<Column prop={user1_col1} />
<Column prop={user1_col2} />
</Row>
<Row prop={user2}>
<Column prop={user2_col1} />
<Column prop={user2_col2} />
</Row>
<TableFooter>
<FooterColumn prop={sum1} />
<FooterColumn prop={sum2} />
</TableFooter>
</Table>
Whenever someone is changing anything in the column property I only have to maintain the state of this value within that Column component. However, I now would like a sum of these values in the FooterColumn component. What is the best way to achieve this?
If I'm going to pass up the state change I must keep states in multiple places and then pass it down, this is a lot of tedious work. Is it best to use EventEmitters or am I missing something?
So, all you need is to keep track of the state in the parent component, and share the state update function with the children:
var Parent = React.createClass({
getInitialState: function() {
return {
users: [
{name: 'Matt', values: [1, 2]},
{name: 'user517153', values: [4, 5]}
]
};
},
updateValue: function(rowId, colId, newValue) {
var newUsersState = this.state;
newUsersState.users[rowId].values[colId] = newValue;
this.setState({users: newUsersState});
},
render: function() {
var rows = this.state.users.map(function(user, r) {
var cols = user.values.map(function(value, c) {
return (
<Column key={c} prop={value} rowId={r} colId={c} onChange={this.updateValue}/>
);
});
return (
<Row key={r} prop={user}>
{cols}
</Row>
);
});
// Yes, it could be more efficient if you did it all in one map/forEach - doing this in a second one for clarity
var footerCols = this.state.users.map(function(user) {
var sum = 0;
user.values.forEach(function(value) { sum+= value; });
return (
<FooterColumn prop={sum} />
);
});
return (
<Table>
{rows}
<TableFooter>
{footerCols}
</TableFooter>
</Table>
);
}
});
In your Column
class, you simply need something along the lines of:
var Column = React.createClass({
onChange: function(event) {
var props = this.props;
var newValue = event.target.value; // Get the new value somehow - this is just an example
props.onChange(props.rowId, props.coldId, newValue);
},
render: function() {
var props = this.props;
return (
<td onChange={this.onChnage}>{props.prop}</td>
);
}
});
Hope that makes sense.