React vs. Plain JavaScriptReact vs. Plain JavaScript

Learn about the differences between using pure JavaScript or a library like React to design and develop web apps.

October 28, 2019

The following is a guest post by Chris Achard, React Instructor. Chris regularly writes and teaches React, Rails, JS, and Node on platforms like Egghead.io and React Screencasts.

Web apps are becoming increasingly complex and dynamic. In response, new tools and libraries like React have been created to speed up the process.

But how is developing a web app with React different than developing an app with just plain JavaScript?

What is ‘plain’ JavaScript?

It’s important to point out that React itself is written in JavaScript, which could lead one to think that writing React is just writing JavaScript.

To set some boundaries, let’s first define what we mean by "plain" JavaScript (also called "vanilla" JavaScript).

React is a library that defines the way apps are written. It does this by setting very clear rules about how data can flow through the app, and how the UI will adapt as a result of that changing data. There are other libraries that set similar boundaries, such as Angular and Vue.

Plain JavaScript (that is, JavaScript written without libraries) on the other hand, doesn’t set any rules about how data can be defined, or how the UI can be changed. That makes apps written without these libraries more freeform and customizable. But going this route can also lead to problems down the road.

The one library that we could be included under the umbrella of "plain JavaScript" would be jQuery. jQuery is a convenient wrapper that goes around existing JavaScript functionality to make it easy and consistent to use across browsers. It doesn’t set the same boundaries as a library like React though—so a jQuery app could fall into the same trap as apps written in plain JS.

The major differences

Since there are so many ways to write vanilla JS, it can be difficult to pin down a list of differences that applies to 100% of apps. But here we’ll define some key differences that apply to many plain JS apps that are written without a framework.

Those differences are:

  1. How the user interface is first created

  2. How functionality is split up across the app

  3. How data is stored on the browser

  4. How the UI is updated

Let’s break down each one of those differences and understand how an app works with and without React.

How the user interface is first created

In plain JS, the initial user interface is generally created in HTML on the server. Meaning, HTML is dynamically created on the server, and might look something like this:

<div>
<h1>Grocery List</h1>
<ul>
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
</div>
COPY

That gets sent to the web browser and displayed—no JavaScript needed yet!

In contrast, a React app will start with a fixed HTML file that looks like this:

<div id="root"></div>
COPY

...which is blank! So how does the UI get created?

Instead of defining the initial UI on the server, the UI gets defined on the browser. So the app starts with a blank container (a div in this case), and then the UI gets loaded into that container.

The UI is defined by a component that returns JSX. JSX looks like HTML, but is actually JavaScript - and might look like this:

function GroceryList(props) {
return (
<div>
<h1>Grocery List</h1>
<ul>
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
</div>
)
};
COPY

And that new GroceryList component gets mounted (or "rendered") into the div container using a library called ReactDOM:

<GroceryList />, <GroceryList />, <GroceryList />, document.getElementById("root") )
COPY

This results in the same initial UI as the plain JS example above except that happens on the browser, instead of beforehand on the server.

How functionality is split up across the app

With a plain JS app, there are no requirements about how you split up functionality or UI components in an application.

For example, our initial grocery list can just be defined in a main index.html file:

<div>
<h1>Grocery List</h1>
<ul id="grocery-list">
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
</div>
COPY

And the code that updates the list might be buried deep in a separate javascript file:

function addItemToList() {
// Add item
}
COPY

This has traditionally been done because splitting the HTML (markup) and JavaScript (functionality) was seen as a "separation of concerns".

However, as the complexity of JavaScript apps has grown, this has caused huge headaches. Because the code that updates a piece of HTML might live in several different JS files across the entire application, developers have to keep all of those files open at once - and they have to "hold in their head" each of those interactions at the same time.

In contrast, React enforces that your app is split into components and that each one of those components maintains all of the code needed to both display and update the UI:

function GroceryList(props) {
function addItem() {
// Add Item
}
return (
<div>
<h1>Grocery List</h1>
<ul>
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
</div>
)
};
COPY

This keeps the update code right next to the display code, and makes complicated apps easier to understand.

It also allows for greater code reuse since generic components can be made and shared across an app.

How data is stored on the browser

Once the initial UI is loaded, the user will be able to interact with your app. For interactions like typing into an input box, that text has to be stored somewhere on the browser before it can be used later (to submit to the backend server, for example).

In a plain JS app, that user data is generally stored in the DOM (Document Object Model).

The Document Object Model (DOM) is created and maintained by the browser itself and represents all of the HTML nodes on the entire page. That includes any data stored on those nodes.

For example, a plain JS app might define an input textbox like this:

<input type="text" placeholder="Enter an item" id="item-input" />
COPY

As the user types into that textbox, the value of what they are typing is stored by the browser.

That means the way the actual input UI changes as the user types is abstracted away from the developer—which is very convenient! But it also means that when the user submits the form, the developer will have to manually extract the value from that input box by finding it in the DOM first, and then extracting the value:

const input = document.getElementById("item-input"); console.log(input.value);
COPY

That may not seem like a very big deal for just one input, but it can get tedious for an entire form. Plus if the id of the input changes, you’ll have to make sure to change it in every single spot where you access that id as well.

In contrast, React uses a technique called "controlled components" to set the text value in a JavaScript object as the user types it.

First, a bit of state has to be defined to hold the input value:

const [itemInput, setItemInput] = useState("");
COPY

And then that set has to be set whenever the input changes. That makes the input box code more complex:

<input type="text" placeholder="Enter an item" value={itemInput} onChange={e => setItemInput(e.target.value)}
COPY

But it makes it much easier to know the current value of the input box in JavaScript, because it’s simply reading the value from memory:

console.log(itemInput);
COPY

So, by not relying on the DOM to store the current application state, React apps have an advantage when it comes to actually using the user data. And that advantage stacks up over time as the app grows.

Storing the entire current state of the app in JS variables (instead of the DOM) is one of the major benefits React apps have over plain JavaScript apps, especially as the complexity of your app grows.

How the UI is updated

The third major difference between plain JS and React apps is how each app responds to user interaction—like a button press to actually add a new item to list—and then updates the UI to reflect that new change.

In a plain JS app, we could add a button next to the input box that has an id:

<input type="text" placeholder="Enter an item" id="item-input" /> <button id="add-button">Add</button>
COPY

and then to respond to that button press, we could first find the button in the DOM (in the same way that we found the input before):

const addButton = document.getElementById("add-button");
COPY

And then set a click listener on that button:

addButton.addEventListener("click", function() {
// Append item
})
COPY

And then inside of that click listener, we could first get the value of the input box using the same method as before. Then to append a new item to the grocery list, we have to find the list in the DOM, create the new item to append, and then finally append that to the end of the list:

(There are libraries that make this a bit easier to do - but this is how you can do it in just plain JavaScript)

addButton.addEventListener("click", function() {
const input = document.getElementById("item-input");
console.log(input.value);
const list = document.getElementById("grocery-list");
const listNode = document.createElement("li");
const textNode = document.createTextNode(input.value);
listNode.appendChild(textNode);
list.appendChild(listNode);
});
COPY

In contrast, a React app will be set up to keep the entire state of the list in a JS variable:

const [items, setItems] = useState(["Milk", "Bread", "Eggs"]);
COPY

Which will then be displayed in JSX by mapping (looping) over each item, and returning a list element for each one:

<ul>
{items.map(item => (
<li key={item}>{item}</li>
))}
</ul>
COPY

Then, the actual button press can be defined right in the function. That means there is no click listener needed, but an onClick attribute can be added to the button itself:

<button onClick={addItem}>Add React</button>
COPY

And all that function has to do is append the new item (which is stored in JS memory) to the existing array of items, using the setItems updater function:

function addItem() { console.log(itemInput); setItems([...items, itemInput]); }
COPY

React will automatically register that there has been a change to the list, and update the UI automatically.

That updater function is the real magic of React. It takes a function from plain JS that looks like this:

addButton.addEventListener("click", function() {
const input = document.getElementById("item-input");
const list = document.getElementById("grocery-list");
const listNode = document.createElement("li");
const textNode = document.createTextNode(input.value);
listNode.appendChild(textNode);
list.appendChild(listNode);
});
COPY

...and condenses it all the way down to a single directive:

function addItem() { setItems([...items, itemInput]); }
COPY

The automatically updating nature of React apps means that you don’t have to go into the DOM to find where to append your items—it just happens automatically for you.

How React is Different

So, we’ve looked at the three major ways React is different than plain JS. In particular, those were:

  1. Plain JS apps usually start with the initial UI created on the server (as HTML), whereas React apps start with a blank HTML page, and dynamically create the initial state in JavaScript.

  2. React requires you to break your UI into components, but plain JS apps can be structured in any way you see fit.

  3. Data for plain JS apps are stored in the DOM itself and has to be found from the DOM before it can be used. React apps store data in regular JavaScript variables.

  4. UI updates in plain JS have to happen by finding the DOM node to update and manually appending or removing elements. React automatically updates the UI based on setting and changing state within the component.

Is React Worth It?

The reason React was created is because it’s easy to get lost in a bit of maze of DOM searches and updates with plain JavaScript.

We saw how complicated it can become to simply append an item to a list with plain JS, and that just compounds across really complex applications.

Also, the way that React forces you to create components really helps you create your app in a more maintainable way.

So for complex apps, a library like React is definitely worth the extra learning curve at the start. It means you can write more maintainable apps with fewer bugs.

And once you take the time to learn it, writing React is faster and more fun as well!


Did you find this helpful? Check out some of our other resources on React:

Like this article? Spread the word.

Want more design articles?

Join our newsletter and get resources, curated content, and design inspiration delivered straight to your inbox.