Contact Us

Leaving the Old Ways - jQuery vs React

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.

Before you go…

If you enjoyed reading this post please share it. You should check out our other publications, you might like them too! We write from time to time about software development, tips and tricks, and how to become a better developer and business person in general. Join us on the journey of constant improvement!

Follow us on Facebook, Twitter, LinkedIn, Medium or DEV.to.

Sasa Blagojevic photo

Sasa Blagojevic

Sasa is a highly driven full stack software developer with background in finance and accounting. A relentless problem solver who is passionate about finding elegant solutions to problems at hand. Writing maintainable and performant code is very important to him. He specializes in PHP and Ruby and all things backend. When he's not writing code he spends his time spreading the gospel of JSGuru.

Powered by an API first CMS.

We collect information about how our Users use and interact with the Site. This may include the pages Users visit most often and when and where Users get error messages. We use these “session state cookies” to help us improve our Site and Services. Blocking or deleting these cookies will not prevent the Site from working.

OK, close this

We collect information about how our Users use and interact with the Site. This may include the pages Users visit most often and when and where Users get error messages. We use these “session state cookies” to help us improve our Site and Services. Blocking or deleting these cookies will not prevent the Site from working.

OK, close this