Check out myAngular article series with live demos and Facebook group Angular - Advanced Topics

Decoupled object models in React

Torgeir "Tor" Helgevold
- JavaScript Developer and Blogger
Published: Mon Feb 23 2015

A common criticism of React seems to be that it's tearing down the barrier between view and object model - better known as separation of concerns. Some are even claiming that React is taking us back in time by reintroducing anti patterns from the past where Html and JavaScript were tightly coupled and intertwined like spaghetti. I find this view to be misguided, and will through a simple example, demonstrate how to integrate decoupled object models in React.

I have previously written a post about decoupled models in Angular. However, there is nothing preventing us from implementing the same decoupled model in a React component. In fact I will take a model very similar to the one I used in my Angular example to demonstrate how it can be done.

Like in the Angular example I will build a simple shopping cart where the user is able to add items and calculate a running price total.

//Shopping Cart function shoppingCart(){ this.itemsToPurchase = []; }; shoppingCart.prototype.addItem = function(name,price){ if(isNaN(price) || name.trim().length === 0){ this.errorMessage = "Invalid input"; this.valid = false; } else{ this.itemsToPurchase.push(new shoppingCartItem(name, price)); this.calculateTotalPrice(); this.errorMessage = ""; this.valid = true; } }; shoppingCart.prototype.calculateTotalPrice = function(){ this.totalPrice = 0; for(var i = 0; i < this.itemsToPurchase.length; i++){ this.totalPrice += this.itemsToPurchase[i].calculatePrice(); } }; //Shopping Cart Item function shoppingCartItem(name, price){ this.price = parseFloat(price); this.name = name; } shoppingCartItem.prototype.calculatePrice = function(){ return this.price; //picture more complex logic here like //discounts and promotions };

The code listing above shows a model consisting of a shopping cart model combined with an item model for each product added to the cart.

By encapsulating the functionality in a decoupled object model we ensure that the code is totally agnostic of how it's used. Meaning, the same code can just as easily be invoked by a unit test or any random UI framework like React, Angular or Knockout.

As you can see from the code below, the React integration is very simple and consists largely of defining the virtual DOM and simple “pass through” of input values to the model.

var ShoppingCartView = React.createClass({ getInitialState: function(){ return {shoppingCart:new shoppingCart()}; }, addItem: function(){ var price = this.refs.productPriceTxt.getDOMNode().value; var name = this.refs.productNameTxt.getDOMNode().value; this.state.shoppingCart.addItem(name,price); this.setState(this.state.shoppingCart.itemsToPurchase); }, render: function(){ var items = this.state.shoppingCart.itemsToPurchase.map(function(item){ return( <ShoppingCartItemView item={item} /> ) }); return( <div> <input ref="productNameTxt" placeholder="Type name of product" /> <input ref="productPriceTxt" placeholder="Type price of product" /> <button onClick={this.addItem}>Add Item</button> <table> {items} </table> <div>Total Price: {this.state.shoppingCart.totalPrice}</div> <div>{this.state.shoppingCart.errorMessage}</div> </div> ); } }); var ShoppingCartItemView = React.createClass({ render: function(){ return( <tr> <td>{this.props.item.name}</td> <td>${this.props.item.price}</td> </tr> ) } });

In conclusion

There is absolutely nothing true about the claim that React encourages spaghetti code and poor coding styles :-)

If you liked this article, share it with your friends on social media:

We also have a new Facebook group about advanced Angular topics.

I invite you to follow me on twitter