I've just created my first set of related classes in React and would like to get feedback from more experienced React developers.
I've used ES and completely vanilla React. The application is a shopping cart where the cart item quantities update the totals.
The one file situation is because it didn't seem to like multiple files, a build will fix this and that is not the scope of this question.
How does the application of BEM in a React context come across? What ways can I improve this, looking specifically at the application of React components, states and props?
I'm not specifically looking at any JavaScript only refactoring (such as those in the total calculation functions) nor at any HTML structure problems.
Pull and run from here - the CSS is also here.
var CartItem = React.createClass({
calculateTotal: function() {
return Number(this.props.price * this.props.qty).toFixed(2);
},
render: function() {
return (
<div key={this.props.key} className='cart-line'>
<div className='cart-line__name'>{this.props.name}</div>
<div className='cart-line__change-qty'>
<a className='cart-line__qty-up' onClick={this.props.onQtyChanged.bind(null, this.props.arrayIndex, '+')}>+</a>
<a className='cart-line__qty-down' onClick={this.props.onQtyChanged.bind(null, this.props.arrayIndex, '-')}>-</a>
</div>
<div className='cart-line__quantity'>{this.props.qty}</div>
<div className='cart-line__price'>£{Number(this.props.price).toFixed(2)}</div>
<div className='cart-line__total'>£{this.calculateTotal()}</div>
</div>
);
}
});
var AllCartItems = React.createClass({
buildRows: function() {
var rows = [];
var onQtyChanged = this.props.onQtyChanged;
var x = 0;
this.props.cartItems.forEach(function(cartItem) {
rows.push(<CartItem key={cartItem.id} arrayIndex={x} name={cartItem.name} qty={cartItem.qty} price={cartItem.price} onQtyChanged={onQtyChanged} />);
x ++;
});
return rows;
},
render: function() {
return (
<section className='all-cart-items'>
<h1 className='all-cart-items__heading'>Cart Items</h1>
<div className='all-cart-items__items'>
{this.buildRows()}
</div>
</section>
);
}
});
var Discount = React.createClass({
render: function() {
return (
<div className='discount'>
<input className='discount__field' type='text' name='discount' defaultValue='0.1'/>
<button className='discount__apply'>Apply Discount</button>
</div>
)
}
});
var TotalRow = React.createClass({
calculateTotal: function(total) {
return Number(total).toFixed(2);
},
render: function() {
return (
<div className='total-row'>
<span className='total-row__label'>{this.props.label}</span>
<span className='total-row__total'>£{this.calculateTotal(this.props.total)}</span>
</div>
);
}
});
var Totals = React.createClass({
discount: function() {
return 0 - this.total() * 0.1;
},
subTotal: function() {
var items = this.props.cartItems;
var subTotal = 0;
for (var x = 0; x < items.length; x ++) {
subTotal += items[x].price * items[x].qty;
}
return subTotal;
},
taxTotal: function() {
return this.subTotal() / 100 * 20;
},
total: function() {
return this.subTotal() + this.taxTotal();
},
youPay: function() {
return this.total() + this.discount()
},
render: function() {
return (
<section className='totals'>
<h1 className='totals__heading'>Totals</h1>
<div className='totals__details'>
<TotalRow label='Sub Total' total={this.subTotal()}/>
<TotalRow label='Discount Value' total=''/>
<TotalRow label='Tax @ 20%' total={this.taxTotal()}/>
<TotalRow label='Grand Total' total={this.total()}/>
<Discount />
<TotalRow label='Discount' total={this.discount()}/>
<TotalRow label='You Pay' total={this.youPay()}/>
</div>
</section>
);
}
});
var Basket = React.createClass({
getInitialState: function() {
return {cartItems};
},
handleQtyChanged: function(cartItemIndex, direction) {
if (direction === '+') {
cartItems[(cartItemIndex)].qty++;
} else {
cartItems[(cartItemIndex)].qty--;
}
this.setState({cartItems});
},
render: function() {
return (
<main>
<AllCartItems cartItems={this.state.cartItems} onQtyChanged={this.handleQtyChanged}/>
<Totals cartItems={this.state.cartItems} />
</main>
);
}
});
React.render(
<Basket cartItems={cartItems} />,
document.getElementById('react-basket')
);