Custom software development & design company

Home

Services

What We Do

View projects we have done

Works

Mobile apps
Mobile apps Need an estimate?

Contact Us

Mobile apps JSGuru's story

About Us

Certifications and awards

Awards

Learn what it is like to work in JSGuru

Careers

Read our

Blog

scroll down

Leaving the Old Ways – jQuery vs React

Sasa Blagojevic

Author at JSGuru

Contrary to popular belief, React’s biggest use cases are not SPAs, it’s the hybrid apps that are most common, and the best fit in my opinion, in this post I will cover how and why I went from a React hater to a React fanboy, and why React is a perfect replacement for jQuery.

I used to have some kind of an inner resistance when React and Vue first started to gain traction and were becoming the de facto standard for building modern UIs.

Yes, I’m purposefully leaving Angular out, even though AngularJS was the pioneer of the front end revolution that brought us web 2.0. 

Angular is philosophically on the completely opposite side of the spectrum, it’s a full-blown SPA framework, whereas React is just a view library, and I’m still not convinced SPAs are the right way and personally I prefer the hybrid approach. 

For all of you that are thinking right now – “And what about Vue?” , Vue would be somewhere in between these two extremes.

Contrary to popular belief, React’s biggest use cases are not SPAs, it’s the hybrid apps that are most common, and the best fit in my opinion. Don’t believe me? Well look what Facebook’s Dan Abramov had to say:

It’s interesting that React became associated so much with SPAs but Facebook isn’t using it for SPAs (except for the Instagram website and some internal tools) – @dan_abramov

One of my major pet peeves was Webpack and all the tooling they brought with themselves.

I held a strong opinion that they were introducing unnecessary complexity to the front end, yes they made us developers feel like rocket scientists with the amount of tweaking we had to do and the number of levers and gears we had to pull and turn to make them run, but at the end of the day, did they really add value to the business?

Did they improve the product and the user experience to warrant a higher maintenance and development cost and a higher barrier of entry for new bloods, when we could have done the same with plain ole jQuery, or even better, vanilla JS? 

After I found out React introduced react-cli I decided to give it another go, and boy oh boy was I pleasantly surprised.

With the introduction of react-cli (and vue-cli) all that nitty-gritty tooling and those build steps that were equivalent of getting a PhD in Computer Science were out of the way for 80-90% of use cases, although you still had to roll up your sleeves and mess around with webpack for some edge cases.

Sure if you’re building something fairly simple, may it be a contact form with an Ajax submit or something entirely different but that is simple enough, vanilla JS is, in my opinion, a sound approach, there is no need to roll out the big guns. You can even go with jQuery, but there is really no need for it in today’s world, but that’s a completely different topic. 

Keep it simple – this should always be your mantra.

In that case, if you were to use a framework, 90% of your code would be the frameworks infrastructure and the rest would be your actual logic. That is a major overkill, you are introducing unnecessary boilerplate and increasing your bundle size which directly impacts performance. Bigger bundle means a lot more bytes have to be sent over the INTERNETZ, so you’re actually costing your business, just because you wanted to use that shiny new thing.

Oh, you think those milliseconds don’t matter much? Well they can quickly add up, especially on high traffic sites, just because today’s machines are powerful doesn’t mean we should be reckless and throw anything at them, we need to be conservative with our resources.

Look at it like this, it’s as if you are building a foundation for a ten story building only to put a tent on it.

React, versus the old way, really comes to shine when you are building complex UIs. 

With React the simplicity of development increases with the complexity of the UI you are building, or in other words, the cost of development is inversely proportional to the complexity in comparison with the vanilla JS/jQuery approach.

Here’s a little graph for all you visual types.

Talk is cheap, let’s get our hands dirty with an example from the real world.

We have an invoice form, aside from the general data like the date of the invoice, the due date of the invoice, subject etc., the user needs to be able to add/remove invoice items.

Invoice items, on the other hand, have the following:

  • name and/or the description of the product/service you’re invoicing, 
  • it’s quantity, 
  • price, 
  • any discount you may give, 
  • any penalty interest that incurred,
  • then we might have VAT tax or sales tax depending on your country’s laws 

and finally, all the calculations that go with the aforementioned.

You see now how a seemingly simple thing can get complicated quickly?

With the old approach, you would have to have a lot of things on your mind, you would need to:

1. Add change event handlers on all the different input fields, and some of them would additionally need to cancel each other out so you would need to track when to detach them.

2. Every time an invoice item is added or removed you would need to manipulate the DOM, by either adding or removing child nodes or writing HTML as a string.

No matter the choice, you’d need to concatenate some HTML and fill it with variables, which can get unruly pretty fast. ECMA 6 string literals do ease this a bit, but still, it can get cumbersome. 

Imagine a designer changes something, on how many places would you need to changes all those bits that you’re glueing together in your vanilla JS code?

Another thing you would need to keep in your mind is that if you manipulate DOM as a string you’re killing all the event handlers on those particular DOM elements. Yep, another gotcha moment.

3. Calculations – every time an invoice item is added or removed you need to calculate its particular values and in addition update the invoice’s subtotal, tax, total, etc. Essentially you would be creating your own state store.

I probably might have missed a thing or two that would pop up while trying to handle this use case the old way, as it usually is, everything sounds simpler on paper until you start to implement it and a whole new spectrum of cases that need to be handled appears.

Using React requires a slight shift in your mindset, in a nutshell, you only need to be concerned with one thing, the state. This simplifies the logic immensely, you are only concerned about your state, that is the only thing you need to manipulate, and your invoice input fields and invoice items will be re-rendered according to the changes in your state. 

Let’s take a look at our simplified code example, this might give you a clearer picture. 

import React from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";

class InvoiceItemForm extends React.Component {

  constructor(props) {
      super(props)

      this.state = {
          itemInput: {
              description: '',
              quantity: 0,
              price: 0,
              subtotal: 0,
              taxRate: 0.17,
              tax: 0,
              total: 0
          },
          invoiceItems: []
      }

      this.handleInputChange = this.handleInputChange.bind(this);
      this.addItem = this.addItem.bind(this);
      this.removeItem = this.removeItem.bind(this);
  }

  handleInputChange(e) {
      let input = (e.target || e.currentTarget);
          input.subtotal = input.price * input.quantity;
          input.tax = input.subtotal * input.taxRate;
          input.total = input.subtotal * (1 + input.taxRate);

      this.setState((state) => { return state.itemInput[input.name] = input.value; });
  }

  addItem() {
      let state = this.state;
          state.items.push(state.itemInput);

          // Clear the last input
          for (let key in state.itemInput) {
              switch (key) {
                  case 'description'
                      state.itemInput[key] = '';
                      break;
                  case 'taxRate':
                      state.itemInput[key] = 0.17;
                      break;
                  default:
                      state.itemInput[key] = 0;
                      break;
              }
          }

      this.setState({itemInput: state.itemInput, items: state.items});
  }

  removeItem(e) {
      let rowIndex = (e.target || e.currentTarget).parentNode.parentNode.rowIndex;

      let items = this.state.items.filter((item, i) => { return i !== rowIndex; });

      this.setState({items : items});
  }

  renderCells(item, rowIndex) {
      let cells = [<td>{rowIndex + 1}</td>];

      let i = 1;
      for (let key in item) {
          cells.push(<td key={i}>{item[key]}</td>);
          i++;
      }

      cells.push(
          <td>
              <button onClick={this.removeItem}>
                  {'Remove Item'}
              </button>
          </td>
      );

      return cells;
  }

  render () {
    return (
        <React.Fragment>
            <div>
                <input
                    name={'description'}
                    value={this.state.itemInput.description}
                    onChange={this.handleInputChange} />
                <input
                    name={'price'}
                    value={this.state.itemInput.price}
                    onChange={this.handleInputChange}>
                <input
                    name={'quantity'}
                    value={this.state.itemInput.quantity}
                    onChange={this.handleInputChange}>
                <input
                    name={'taxRate'}
                    value={this.state.itemInput.taxRate}
                    onChange={this.handleInputChange}>
                <input
                    name={'subtotal'}
                    disabled={true}
                    value={this.state.itemInput.subtotal}
                    onChange={this.handleInputChange}>
                <input
                    name={'tax'}
                    disabled={true}
                    value={this.state.itemInput.tax}
                    onChange={this.handleInputChange}>
                <input
                    name={'total'}
                    disabled={true}
                    value={this.state.itemInput.total}
                    onChange={this.handleInputChange}>
            </div>
            <table>
                <thead>
                    <tr>
                        <th>Item no.</th>
                        <th>Description</th>
                        <th>Price</th>
                        <th>Quantity</th>
                        <th>Tax Rate</th>
                        <th>Subtotal</th>
                        <th>Tax</th>
                        <th>Total</th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                    {
                        this.state.items.map((item, i) => {
                            return (
                                <tr key={i}>
                                    {this.renderCells(item, i)}
                                </tr>
                            );
                        })
                    }
                </tbody>
            </table>
        </React.Fragment>
    );
  }
}

export default InvoiceItemForm

Vuoala, that’s it!

Hey, do you have a jQuery app you would like to migrate or are you just trying to figure out which framework would be best for your next million dollar idea? Contact us at info@jsguru.io, and let that be our headache.