6
\$\begingroup\$

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')
);
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 7, 2015 at 14:43
\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

First things First

I cloned it and run it as you wrote in README.md file, As a frontend project it'll be better if you used something like npm to run your project.

things you can do better:

When to use map over forEach?

If you want to return a new array instead of change the current, you can use map function. in this example you don't have to create a new array then change in it.

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

You can simply do this

 buildRows: function() {
 return this.props.cartItems.map((cartItem, indx) =>
 <CartItem
 key={cartItem.id}
 arrayIndex={indx}
 name={cartItem.name}
 qty={cartItem.qty}
 price={cartItem.price}
 onQtyChanged={this.props.onQtyChanged} />
 );
 },

You can use Object destruction

Object destruction is great for using object attributes without repeating the object name. you can use it in the previous example like this.

buildRows: function() {
 const {onQtyChanged, cartItems} = this.props;
 return cartItems.map(({id, name, qty, price}, indx) =>
 <CartItem
 key={id}
 arrayIndex={indx}
 name={name}
 qty={qty}
 price={price}
 onQtyChanged={onQtyChanged}
 />
 );
 },

Use const and let instead of var

to avoid mutation or scope mistakes.

Ternary operator instead of if condition

Use ternary operators when you make just one line change like this

handleQtyChanged: function(cartItemIndex, direction) {
 /* old
 if (direction === '+') {
 cartItems[(cartItemIndex)].qty++;
 } else {
 cartItems[(cartItemIndex)].qty--;
 }
 */
 // new
 direction === '+'
 ? cartItems[(cartItemIndex)].qty++
 : cartItems[(cartItemIndex)].qty--;
 this.setState({cartItems});
 },
answered Feb 9, 2019 at 21:00
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.