react beyond basics
introduction

Introduction

You are going to be surprised how easy it is to learn the React.js API and start creating useful applications with it right away! This book will teach you the most important and fundamental design concepts of React, its main building blocks, and how to use it to build simple web applications.

In this first introductory chapter of the book, we will talk about what is React, what learning React requires, and why React is a great library to learn. We will go through a few main design concepts about React. We will also talk briefly about Node.js and why it is the popular back-end framework to work with React.

Chapters 2 and 3 are the "theory" part of this book. I jammed most of the theory that you need to learn about React in Chapter 2 and then in Chapter 3 I walk you through a simple example to make sure that you map the theory that you learn into some interactive User Interface (UI). The examples presented in Chapters 2 and 3 are not very useful ones. They are designed and intended to explain certain concepts. The fun begins in Chapter 4.

In Chapters 4, 5, 6, and 7, we will create four different browser games. These games will be simple ones that are based on simple user interactions and can be easily rendered in standard browsers. My 6-year old can play them. I actually picked these games mostly on the criteria that they can be played by 6-year old children. However, many grownups reported having fun playing these games. Do not get addicted though. You have been warned.

You can play the final versions of all the games that we will build in this book at jscomplete.com/react-games

Learning how to design and build simple games like these will make you focus entirely on the React API itself because each of these games will have a small state and no data dependencies at all. This book is not meant to teach you how to build data-driven applications and work with asynchronous APIs. You need to master the React API first.

Building simple game apps beats building abstract and "TODO" apps on so many levels. I have always been against the use of abstract foo-bar types of examples because they lack context and engagement. Learners need to like what they are building. They need to accomplish something at the end of each phase in their learning journey. They need to make design decisions and see progress on features they can relate to.

However, since this book targets React beginners, we need to cover some theory first. If you are comfortable with the React API, feel free to skip all the way to Chapter 4.

Please note that this book has a 100% focus on the React (and ReactDOM) API. Whenever I need some complex JavaScript logic, I will either use a library like lodash or provide a ready function for that logic. I will also provide starting HTML/CSS templates so that we don’t waste time on these.

ReactDOM, by the way, is the library that we use with React to render UIs in a browser’s DOM. Since this book is targeted at building UIs in a browser, mentions of React usually mean both React and ReactDOM.

This book will also not cover any of the React ecosystem of tools and libraries like Redux or React Router. I have also skipped using React helper libraries like PropTypes. This does not mean that you should not use these libraries. It just means that for the duration of this book your focus should be entirely on the React API.

The Path to Learning React

First and foremost, you need to make peace with the fact that you have to learn more than just React to work with React. This is a good thing. React is a small library and it is not the answer to everything. However, you need to identify whether what you are learning is React or not, mainly so that you do not get confused about your effort to learn React itself.

I think a programmer who is comfortable with HTML and one other programming language will be able to pick up 100% of the React API in one day or less. A beginner programmer should be good enough with React in about a week. This is not counting the tools and other libraries that complete React like Redux or React Router.

There is an important question about the order with which you need to learn things. This order would vary based on what skills you have. It goes without saying that you need a solid understanding of JavaScript itself first, and of course HTML as well.

I like to be specific about the level of HTML/JavaScript that you need before learning React and ReactDOM: If you do not know what the DOM is, or if you do not understand the concept of children and parent nodes, or if you do not know how to define simple event handlers on DOM elements, you are not ready for React. If you do not know how to map or reduce an array, or if you do not understand the concept of closures and callbacks, or if seeing "this" in JavaScript code confuses you, you are not ready for React and you still have a lot to do in JavaScript land. I recommend that you read a book about JavaScript first. If you like my style of writing, you might like my book about JavaScript: Let’s Learn Coding with Modern JavaScript.

Refreshing your knowledge on JavaScript first would not hurt, especially because you need to learn ES2015+ (ES6, ES7, etc.).

While you can use React without learning the modern JavaScript capabilities, these capabilities make JavaScript a much better language. Also, most of the examples, courses, and tutorials you will find on the internet use the modern JavaScript features.

Modern JavaScript has a lot of features. If you want a short list, here is one that includes only the features that are especially relevant to React:

  • The new object literal syntax

  • Template strings

  • Block scopes and the use of let and const

  • Arrow functions

  • Destructuring objects and arrays in variables and arguments

  • Default function arguments and the REST/ SPREAD operator

  • Classes (which are used slightly in defining component, but to be avoided otherwise)

  • Static and instance properties for a class. The new class-field syntax to define functions with the arrow syntax and avoid the binding problem

  • Promise objects and how to use them with async / await

  • Importing and exporting modules. Default exports and named exports

You do not have to start with these features, but you do need to eventually learn them.

To be a productive React developer, besides the modern JavaScript features above, you need to learn the following:

  • The APIs of React, ReactDOM, ReactDOMServer: These are not big APIs really. We are talking about maybe 25 different fields and you would rarely use them all. The official React documentation is a very good starting point and this book entirely focuses on the React and ReactDOM APIs.

  • Node and npm (or yarn): the reason you need to learn these (for React) is that there are a ton of tools that are hosted at npmjs.org that would make your life easy. Also, since Node allows you to execute JavaScript on your servers, you can reuse your front-end React code on the server (Isomorphic/Universal applications). The last section in this chapter (Why Node) will explain this point with some details.

  • React ecosystem libraries like Redux and React Router: Since React is just the UI language, you will need other tools and libraries to complete the picture. However, do not start with these libraries until you are very comfortable with React itself.

Also, right after getting comfortable with the raw concepts of React itself, build a React Native app. You will only truly appreciate the beauty of React once you do that. Trust me.

During your learning process, the best thing you can possibly do is build stuff with your own hands. Do not copy/paste examples and do not follow instructions blindly. Mirror the instructions to build something else (ideally, something you care about).

While understanding the games we will build in this book, try to come up with different game ideas and implement them as well. Try to improve the book’s games and add more features beyond what is presented in this book. Each game will have a Bonus Challenges last section. Try to implement all of these challenges and do not be afraid to make mistakes. Building things with your hand is the only truly helpful strategy when it comes to learning programming in general. React is no different.

You don’t learn to walk by following rules. You learn by doing, and by falling over.
— Richard Branson

Why React

I am a big fan of starting with WHY, so before you dive in and write your first React component, let me make sure that you know why committing to learning React is a very good thing that you are doing.

Let’s start with React’s official definition. It states that it is a JavaScript library for building User Interfaces. It is important to understand the two different parts of this definition:

  • React is a JavaScript library. It is not a framework. It is not a complete solution and we will often need to use more libraries with React to form any solution. React does not assume anything about the other parts in any solution. It focuses on just one thing and on doing that thing very well.

  • The thing that React does very well is the second part of the definition: building User Interfaces. A User Interface is anything we put in front of users to have them interact with a machine. User Interfaces are everywhere, from the simple buttons on a microwave to the dashboard of a space shuttle. If the device we are trying to interface can understand JavaScript, we can use React to describe a User Interface for it.

Since Web browsers understand JavaScript, we can use React to describe Web User Interfaces. I like to use the word describe here because that is what we basically do with React. We just tell React what we want, and it will build the actual User Interfaces, on our behalf, in the Web browser. Without React or similar libraries, we would need to manually build User Interfaces with native Web APIs and JavaScript and that is not as easy.

When you hear the statement that "React is declarative," this is exactly what it means: we describe User Interfaces with React and tell it what we want (not how to do it). React will take care of the "how" and translate our declarative descriptions (which we write in the React language) to actual User Interfaces in the browser. React shares this simple declarative power with HTML itself, but with React we get to be declarative for HTML interfaces that represent dynamic data, not just static data.

How exactly is not being a framework a good thing?

I love big frameworks (and I cannot lie). Frameworks serve a great purpose, especially for young teams and startups. When working with a framework, many smart design decisions are already made for you, which gives you a clear path to focus on writing good application-level logic.

However, frameworks come with some disadvantages as well. For experienced developers working on large codebases, these disadvantages are sometimes a deal breaker. Let me name two of the important disadvantages about using a framework:

  • Frameworks are not flexible, although some claim to be. Frameworks want you to code everything a certain way; if you try to deviate from that way, the framework usually ends up fighting you about it.

  • Frameworks are large and full of features. If you need to use only a small piece of them, you have to include the whole thing anyway.

Admittedly, the latter point is changing today but it is still not ideal. Some frameworks are going modular, which I think is great, but I am a big fan of the pure Unix philosophy:

Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.
— Doug McIlroy

React follows the Unix philosophy because it is a small library that focuses on just one thing. There is a lot of buzz around the performance of React’s virtual DOM, but I don’t think that is the greatest feature in React. The virtual DOM performance is a nice plus. What React does exceptionally well is creating a common language between developers and browsers that allows developers to declaratively describe user interfaces and model the state of these interfaces instead of managing UI transactions on them.

React taught developers and browsers a new language that they can use to communicate with each other: The language of User Interface outcomes.

React is very popular today and I think it is taking over the front-end development. Here is a summary of the reasons why I think React gained this massive popularity:

  • Working with the DOM API is hard. React basically gives developers the ability to work with a virtual browser that is friendlier than the real browser.

  • React is just JavaScript. There is a very small API to learn, and after that your JavaScript skills are what make you a better React developer. There are no barriers to entry.

  • Learning React pays off big-time for iOS and Android mobile applications as well. React Native allows you to use your React skills to build native mobile applications. You can even share some logic between your web, iOS, and Android applications.

  • The React team at Facebook tests all improvements and new features that get introduced to React right there on facebook.com, which increases the trust in the library among the community. It’s rare to see big and serious bugs in React releases because they only get released after thorough production testing at Facebook.

  • Most importantly, React enables developers to declaratively describe their User Interfaces and model the state of those interfaces. This means instead of coming up with steps to describe transactions on interfaces, developers just describe the interfaces in terms of a final state (like a function). When transactions happen to that state, React takes care of updating the User Interfaces based on that.

If someone asked you to give ONE reason why React is worth learning, this last one is the one.

In the next section, we will cover more reasons behind React’s rising popularity. These include the many great design concepts behind it. One big design concept is React’s Virtual DOM (which powers its reconciliation algorithm). I will walk you through an example to show the actual practical value of having such an algorithm at your command.

React’s Design Concepts

React has 3 main technical design concepts that drive its popularity:

1 – Reusable, composable, and stateful components

In React, we describe User Interfaces using components. You can think of components as simple functions (in any programming language). We call functions with some input and they give us some output. We can reuse functions as needed and compose bigger functions from smaller ones.

Components are exactly the same; we call their input "properties" and "state" and a component output is a description of a User Interface. We can reuse a single component in multiple User Interfaces and components can contain other components.

However, unlike pure functions, a class-based React component can have a private state to hold data that may change over the lifecycle of the component.

2 – Reactive Updates

React’s name is the simple explanation for this concept. When the state of a React component (the input) changes, the User Interface it represents (the output) changes as well. This change in the description of the User Interface has to be reflected in the device we are working with.

In a browser, we need to regenerate the HTML views in the DOM. With React, we don’t need to worry about how to reflect these changes or even manage when to take changes to the browser; React will simply react to the state changes and automatically update the DOM when needed.

3 – The Virtual Representation of Views in Memory

With React, we write HTML using JavaScript. We rely on the power of JavaScript to generate HTML that depends on some data rather than enhancing HTML to make it work with that data. Enhancing HTML is what other JavaScript frameworks usually do. For example, Angular extends HTML with features like loops, conditionals, and others.

When we receive just the data from the server (in the background, with AJAX), we need something more than HTML to work with that data. It is either using an enhanced HTML to be parsed by JavaScript or using the power of JavaScript itself to generate the HTML. Both approaches have advantages and disadvantages. React embraces the latter one.

There is one major advantage that can make the case for React’s approach by itself; using JavaScript to render HTML makes it easy for React to keep a virtual representation of HTML in memory (which is commonly known as The Virtual DOM). React uses the Virtual DOM to render an HTML tree virtually first, and then every time a state changes and we get a new HTML tree that needs to be taken to the browser’s DOM, instead of writing the whole new tree, React will only write the difference between the new tree and the previous tree (since React has both trees in memory). This process is known as Tree Reconciliation.

In the following example, we will focus on this last concept and see a simple practical example of the tree reconciliation process and the big difference it makes. We will write the same HTML example twice, first using native Web APIs and vanilla JavaScript, and then we will see how to describe the same HTML tree with React.

To purely focus on this last concept, we will not be using components and we will mock a state change operation using a JavaScript timer. We are also not going to use JSX, although using JSX will make for a much simpler code. I use JSX all the time when I write React but working with the React API directly in this example will hopefully make you understand this concept much better. We will talk about JSX in the next chapter.

Example of React’s Reconciliation Algorithm

To follow along with this example, you can use the following jsComplete playground session: jsdrops.com/rsy1.1

In that session, you should see a very simple HTML element rendered to the display using 2 methods:

1) Using the Web DOM API directly
document.getElementById('mountNode').innerHTML = `
  <div>
    Hello HTML
  </div>
`;
2) Using React’s API
ReactDOM.render(
  React.createElement(
    'div',
    null,
    'Hello React',
  ),
  document.getElementById('mountNode2'),
);

This example uses the render method from the ReactDOM API and the createElement method from the React API. These are the core API methods in React applications. In fact, a React web application cannot exist without using both of these methods. Let me briefly explain them:

ReactDOM.render

This is basically the entry point for a React application into the browser’s DOM. It has 2 arguments:

  1. The first argument is WHAT to render to the browser. This is always a "React element".

  2. The second argument is WHERE to render that React element in the browser. This has to be a valid DOM node that exists in the statically rendered HTML. The example above uses a special mountNode2 element which exists in the display area.

What exactly is a React element? It’s a VIRTUAL element describing a DOM element. It’s what the createElement API method returns.

React.createElement

Instead of working with strings to represent DOM elements (as in the native DOM example above) in React we represent DOM elements with objects using calls to the React.createElement method. We call these objects React elements.

The React.createElement function has many arguments:

  1. The first argument is the HTML "tag" for the DOM element to represent, which is div in this example.

  2. The second argument is for any attributes (like id, href, title, etc) we want the DOM element to have. The simple div we’re using has no attributes, so we used null in there.

  3. The third argument is the content of the DOM element. We’ve put a "Hello React" string in there.

React.createElement can also be used to create elements from React components. We will see examples of that in the next Chapter.

React elements are created in memory. To actually make a React element show up in the DOM, we use the ReactDOM.render method which will do many things to figure out the most optimal way to reflect the state of a React element into the actual DOM tree in the browser.

When you execute the 2 methods in this code session, you’ll see a "Hello HTML" box and a "Hello React box":

picture2

Nesting React Elements

We have two nodes, one being controlled with the DOM API directly and another being controlled with the React API (which in turn uses the DOM API). The only major difference between the ways we are building these two nodes in the browser is that in the HTML version we used a string to represent the content, while in the React version we used pure JavaScript calls and represented the content with an object instead of a string.

No matter how complicated the HTML User Interface is going to get, when using React, every HTML element will be represented with a React element.

Let’s add more HTML elements to this simple User Interface. Let’s add a text box to read input from the user. For the HTML version you can just inject the new element’s tag directly inside the template:

document.getElementById('mountNode').innerHTML = `
  <div>
    Hello HTML
    <input />
  </div>
`;

To do the same with React you can add more arguments after the third argument for React.createElement above. To match what’s in the native DOM example so far, we can add a fourth argument that is another React.createElement call that renders an input element:

ReactDOM.render(
  React.createElement(
    "div",
    null,
    "Hello React ",
    React.createElement("input")
  ),
  document.getElementById('mountNode2'),
);

Let’s also render the current time in both versions. Let’s put it in a pre element (just to give it monospace font in the playground). You can use new Date().toLocaleTimeString() to display a simple time string. Here’s what you need to do for the native DOM version:

document.getElementById('mountNode1').innerHTML = `
  <div>
    Hello HTML
    <input />
    <pre>${new Date().toLocaleTimeString()}</p>
  </div>
`;

To do the same in React, we add a fifth argument to the top-level div element. This new fifth argument is another React.createElement call, this time using a pre tag with the new Date().toLocaleTimeString() string for content:

ReactDOM.render(
  React.createElement(
    "div",
    null,
    "Hello React ",
    React.createElement("input"),
    React.createElement(
      "pre",
      null,
      new Date().toLocaleTimeString()
    )
  ),
  document.getElementById('mountNode2'),
);

Both versions are still rendering the exact same HTML in the browser.

picture3

As you’re probably thinking by now, using React is a lot harder than the simple and familiar native way. What is it that React does so well that is worth giving up the familiar HTML and having to learn a new API to write what can be simply written in HTML?

The answer is not about rendering the first HTML view. It is about what we need to do to update any existing view in the DOM.

Updating React Elements

Let’s do an update operation on the DOM trees that we have so far. Let’s simply make the time string tick every second.

We can easily repeat a JavaScript function call in a browser using the setInterval Web timer API. So, let’s put all of our DOM manipulations for both versions into a function, name it render, and use it in a setInterval call to make it repeat every second.

Here is the full final code for this example:

Code available at jsdrops.com/rsy1.2
const render = () => {
  document.getElementById('mountNode').innerHTML = `
    <div>
      Hello HTML
      <input />
      <pre>${new Date().toLocaleTimeString()}</pre>
    </div>
  `;

  ReactDOM.render(
    React.createElement(
      'div',
      null,
      'Hello React',
      React.createElement('input', null),
      React.createElement('pre', null, new Date().toLocaleTimeString())
    ),
    document.getElementById('mountNode2')
  );
};

setInterval(render, 1000);

Check out the result of executing this code at jsdrops.com/rsy1.2 and notice how the time string is ticking every second in both versions. We are now updating our User Interface in the DOM.

This is the moment when React will potentially blow your mind. If you try to type something in the text box of the native DOM version, you will not be able to. This is very much expected because we are basically throwing away the whole DOM node on every tick and regenerating it. However, if you try to type something in the text box that is rendered with React, you can certainly do so!

Although the whole React rendering code is within the ticking timer, React is changing only the content of the pre element and not the whole DOM tree. This is why the text input box was not regenerated and we were able to type in it.

You can see the different ways we are updating the DOM visually if you inspect the two DOM nodes in a Chrome DevTools elements panel. The Chrome DevTools highlight any DOM elements that get updated. You will see how we are regenerating the entire mountNode element with every tick, while React is smartly only regenerating the pre tag in the mountNode2 element.

picture4

This is React’s smart diffing algorithm in action. It only regenerates in its DOM node what actually needs to be regenerated while it keeps everything else the same. This diffing process is possible because of React’s virtual DOM and the fact that we have a representation of our User Interface in memory (because we wrote in JavaScript).

Using the virtual DOM, React keeps the last DOM version in memory and when it has a new one to take to the browser, that new DOM version will also be in memory so React can compute the difference between the new and the old versions (in this example, the difference was the time string in the pre element).

React will then instruct the browser to update only the computed diff and not the whole DOM node. No matter how many times we regenerate our interface, React will take to the browser only the new "partial" updates.

Not only is this method a lot more efficient, but it also removes a big layer of complexity about the way we think about updating User Interfaces. Having React do all the computations about whether we should or should not update the DOM enables us to focus on thinking about our data (state) and the way to describe a User Interface for it. We then manage the updates on the data state as needed without worrying about the steps needed to reflect these updates in the actual User Interface in the browser (because we know React will do exactly that and it will do that in an efficient way!)

Why Node

Some people mistakenly assume that Node is required in order to use React. It is not. You do not need Node to run a React project. You do not even need a browser.

Okay, you will probably need a browser to learn React. React was initially made for the web User Interface and it is most popular there. This is why we have the ReactDOM library that works with a browser’s DOM. Just remember that React today is also popular for non-Web interfaces like iOS, Android, virtual reality, and even command line interfaces.

Node is the most popular platform for tools to make working with React easier. Node is also a popular platform to run a web server that can host React applications. However, even if you do not host your React applications on Node, you can still use Node for the tools it offers. For example, you can host your React application with Ruby on Rails and use Node to build assets for the Rails Asset Pipeline.

The Webpack Node package makes it very easy to bundle your multi-file React application into a single file for production and compile JSX (with Babel) during that process. This is an example of a Node tool that you can use on its own. You do not need a Node web server to work with Webpack.

However, there are many reasons to pick Node over other options as the web server to host your React applications. Let me highlight the most important ones:

  • Most of the React examples and projects you will find on the web are based on Node. Getting help is easier when your project is using Node.

  • Node is JavaScript, which you are already using (with React). You do not need to invest in any other languages. Using the same language allows for true code sharing between server-side and client-side code. You will even stop saying server-side and client-side eventually. It is all just JavaScript that is used on both sides. Hiring for your project also becomes easier because, well, JavaScript is popular.

  • Most importantly: you can execute your React front-end code in a Node environment. This is the easiest option to do server-side rendering and have Universal/Isomorphic Applications.

You can do server-side rendering with other languages, but it would not be as easy as Node. The ReactDOM library has a component that is designed to work with Node to make server-side rendering as easy as a few lines of code.

Say that you have a React application that you render to the DOM with this line:

ReactDOM.render(<App data={DATA} />, mountNode);

The same React application can be rendered to an HTML string for server-side rendering using this simple code in a Node-based web-server:

const ReactDOMServer = require('react-dom/server');

const html = ReactDOMServer.renderToString(
  <App data={DATA} />
);

// In the server HTTP handler:
// Write the html variable to the web response object

You can take this resulting html string and use it as the initial HTML of your application and you would be done. Your application will now work before the JavaScript on your clients' browsers even wakes up.

Whether you do server-side rendering with Node or other options, it is a great win on two very important levels:

  • It will make your Web server SEO-friendly. Search engines will see the actual content instead of an empty HTML that loads a JavaScript bundle file. (Note: search engines are getting better at executing JavaScript, but they are not completely there yet.)

  • It will improve the performance of your Web application on slow and limited devices. With server-rendered content, these devices will have something to start with while they slowly parse the client-side JavaScript application. Even after parsing that application, React on the client-side will initially do nothing because it has the exact same content as what was already mounted in the browser through server-rendered HTML.

If you are starting a React project from scratch today, Node would be the best option. It just makes every task you need to do around your React project much easier. Just make sure that you learn the Node runtime before you use it. I wrote a book about exactly that: Node.js Beyond the Basics.

If you cannot use Node as your web server, you can still use it to perform server-side rendering externally and link the output it gives you to your non-Node web server.