Reputation: 7129
This is my first venture into React territory, so I'm sure my problem is a simple newbie one. As an exercise I'm trying to convert an existing working web application to use React. I have a ProductTable which displays a list of products. It has a 'selectedProducts' field as part of its state, which gets updated whenever the product selection changes. My assumption was that changing this value (state) should cause a re-rendering with any new selection.
On first display, the component displays successfully and correctly shows the list of products. However, when a change is made to the selection, what is displayed on screen does not change. Yet from console logging and use of React tools in Chrome, I can see that the 'selectedProducts' field state has indeed changed, and in fact a console log entry in the render method shows that render for the component is in fact being called, with the new selection. But it's not changing what's displayed on screen - the table continues to show the old selection of products - and I really can't figure that out.
Any suggestions as to where to look? I appreciate it might be clearer with some code here but it's slightly difficult to present it in a concise way given that it's a conversion of an existing web application, so I hope my description above is sufficient to suggest something to the experts here.
EDIT: Code of component added here. As you will see, notification is done by means of pub/sub. I've stuck with the global 'productSelection' object for now, but that would be refactored in due course. At the moment the idea is that some other code makes changes to that global variable and then notifies the ProductTable component via pub/sub. As I mentioned, the notification is working fine, the 'selectedProducts' variable is clearly being changed and render is being run - but no visible change is occurring.
var ProductTable = React.createClass({
getInitialState: function () {
return {
selectedProducts: [],
};
},
componentWillMount: function(){
this.pubsubToken = Arbiter.subscribe('products/selection', function() {
// update my selection when there is a message
console.log("Setting selection to "+productSelection.length);
this.setState({ selectedProducts: productSelection });
}.bind(this));
},
componentWillUnmount:function(){
Arbiter.unsubscribe(this.pubsubToken);
},
render: function () {
var rows = this.state.selectedProducts.map(function (product, i) {
return <ProductRow key={product.code} product={product}/>;
});
console.log("Running render for ProductTable with "+rows.length+" rows");
return (
<div>
<label htmlFor="products" id="productsLabel">Available products (click or double-click to select):</label>
<table id="products" className="st-container">
<thead>
<tr>
<td className="st-head" style={{padding:"0px 18px 0px 0px"}}>
<table cellSpacing="0" cellPadding="0" border="0" className="st-head-table" style={{width: "100%"}}>
<thead>
<tr>
<th className="rem" colSpan="0"></th>
<th className="code" colSpan="0">Code</th>
<th className="name" colSpan="0">Name</th>
<th className="pack" colSpan="0">Pack</th>
<th className="size" colSpan="0">Size</th>
<th className="attribs" colSpan="0"></th>
<th className="price" colSpan="0">Price</th>
<th className="unit" colSpan="0">Unit</th>
<th className="rrp" colSpan="0">RRP</th>
<th className="vat" colSpan="0">VAT</th>
</tr>
</thead>
</table>
</td>
</tr>
</thead>
<tbody>
<tr>
<td className="st-body" style={{padding:"0px"}}>
<div className="st-body-scroll" style={{overflowY: "scroll", maxHeight: "250px"}}>
<table cellSpacing="0" cellPadding="0" border="0" className="st-body-table" style={{width: "100%"}}>
<tbody id="productRows">
${rows}
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>
);
}
});
Upvotes: 1
Views: 2730
Reputation: 7055
Ok I see, you need to use componentDidMount instead of componentWillMount because, as stated in the doc : If you call setState within this method, render() will see the updated state and will be executed only once despite the state change.
https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount
Use componentDidMount and everything should be fine.
Edit: you don't need ${rows} but just {rows}. Also I would suggest you check your new data, are they really different form the initial one ?
Upvotes: 2