DEV Community

Cover image for React-Reusable Components
mr chedda
mr chedda

Posted on • Updated on

React-Reusable Components

I'll admit I'm only a year into professionally writing React but I've been working on a production codebase that was written with hardly any reusable components among other conventions that I find odd.

That said I am going to share my general philosophy on the value and importance of custom components which I picked up from a different codebase prior to working on the current one.

In the current codebase I'm working in, custom components are sparse. More-so, the UI is built with native html tags (i.e. <div>, <span>, etc.) in the main component (i.e. CheckoutPage). Furthermore, sometimes values are not stored in a local variable when fetched from an api call; rather rendered as:

<div className="total__price">${item.total_cents.toFixed(2)}</div>
Enter fullscreen mode Exit fullscreen mode

As a one-liner it seems innocently benign but as the file grows for the entire UI on a particular feature, all you see are divs, spans, all over the place that becomes too noisy as I'm having to read classNames to begin to understand what's going on. For example....

Common markup I see on a daily:

LineItems.js

<div className="flex col space-between container">
  <div className="flex line-item line-item__container">
    <span>Subtotal</span>
    <span>${(checkout.sub_total_cents / 100).toFixed(2)}</span>
  </div>
 <div className="flex line-item line-item__container">
    <span>Tax</span>
    <span>${(item.tax_total_cents / 100).toFixed(2)}</span>
  </div>
  {checkout.discount_total_cents > 0 && 
    <div className="flex line-item line-item__container">
      <span className="margin-right-auto">Discounts</span>
       <span className="line-through">{checkout.previous_price / 100).toFixed(2)}</span> 
       <span>${(checkout.total_discounts_cents / 100).toFixed(2)}</span>
    </div>
  }
  /* and many more line items ... */
</div>

Enter fullscreen mode Exit fullscreen mode

When I see the above snippet, I see a few optimizations that can make this more readable and reusable should requirements change (as they usually do). Oh and I forgot to mention there is one global stylesheet for all components in the application that is 6000+ lines long with tons and tons and tons of nesting. 😔

Quick Assessment

  • the line item can be a componentized
  • I like to use the classnames package along with css modules
  • store values in a variable

My proposed optimization:

1) Abstract the line item

LineItem.js

import {flex, space_between} from 'assets/css/flex.module.scss';
import {strikeThrough, textBold} from 'assets/css/utils.module.scss';
import {secondary} from 'components/common/text/text.module.scss';
import {formatPrice} from 'helpers';
import classnames from 'classnames';

const LineItem = ({label, value, hasDiscount, previousPrice, bold}) => {
    return (
      <div className={classnames(flex, space_between, {[textBold]: bold})}>
        <p className={classnames({[margin_right_auto]: hasDiscount})}>{label}</p>
        {hasDiscount && (
            <p className={classnames(strikeThrough, secondary)}>${formatPrice(previousPrice)}</p>
         )}
        <p>${value}</p>
      </div>
    )}

export default LineItem;
Enter fullscreen mode Exit fullscreen mode

2) Use the Line Item component

LineItems.js

import {flex, space_between} from 'assets/css/flex.module.scss';
import {formatPrice} from 'helpers';
import LineItem from './LineItem';

const LineItems = ({checkout}) => {
  const subtotal = formatPrice(checkout?.sub_total)
  const discounts = formatPrice(checkout?.discount_total_cents)
  const hasDiscount = checkout?.discount_total_cents > 0
  const previousPrice = formatPrice(checkout?.total_cents - checkout?.discount_total_cents)
  const tax = formatPrice(checkout?.tax_cents)
  const total = formatPrice(checkout.total_cents)

  <div>
    <LineItem label="Subtotal" value={subtotal}/>
    <LineItem label="Tax" value={tax}/>
    {hasDiscounts && (
      <LineItem 
         label="Discounts" 
         value={discounts} 
         previousPrice={previousPrice} 
         hasDiscount 
      /> 
    )}
    <LineItem label="Total" value={total} bold/>
  </div>
  /* and many more line items ... */
}
Enter fullscreen mode Exit fullscreen mode

Why, in my opinion, this is a better approach

After componentizing the line item, reading LineItems.js is much more clear as to what is being rendered and is noise-free. The user of LineItem merely has to look at what LineItem expects (props) or look at how it's currently being used to simply add a new Service Charge line item should The Product team wish to add it to "Checkout" AND the "Order Receipt".

Conclusion

Bear in mind – this is a simplified code snippet to get my point across. I understand some people are of the school of thought that abstracting the line item to a reusable component is over abstracting; I don't believe so. It is my belief that once the component is created and well-defined, any new dev that joins the team can easily understand what LineItems is rendering and add a new line item LineItem.js within a matter of seconds. Efficiency..... Efficiency is the value and importance of this approach.

Please let me know what you guys think. Is this over abstracting or do you think this is good practice? Also, are you still using Class components versus Functional Components in 2021? Let me know. Thanks.

Top comments (0)