A Complete Beginner's Guide to React

A Complete Beginner's Guide to React

Learn React.js in simple and easy steps starting from basic to advanced concepts with examples

Learn React.js in simple and easy steps starting from basic to advanced concepts with examples

I want to get back into writing more code-heavy content, and React is one of my favorite technologies, so I thought I would create a React intro! This post requires knowledge of HTML and JavaScript -- I am of the firm opinion that you should know these before moving on to libraries like React!

What is React

React is a JavaScript library build in 2013 by the Facebook development team to make user interfaces more modular (or reusable) and easier to maintain. According to React's website, it is used to "Build encapsulated components that manage their own state, then compose them to make complex UIs."

I'm going to use a lot of Facebook examples throughout this post since they wrote React in the first place!

Remember when Facebook moved from just likes to reactions? Instead of just being able to like posts, you can now react with a heart, or a smiley face, or a like to any post. If those reactions were primarily made in HTML, it would be a tremendous amount of work to change all of those likes to reactions and to make sure that they work.

This is where React comes in -- instead of implementing the "separation of concerns" that gets impressed upon developers from day one, we have a different architecture in React that increases modularity based on a component structure instead of separating the different programming languages.

Today, we'll keep the CSS separate, but you can even make that component specific if you want!### React vs. Vanilla JavaScript

When we talk about "vanilla" JavaScript, we are normally talking about writing JavaScript code that doesn't use additional libraries like JQuery, React, Angular, or Vue. If you would like to read more about those and what a framework is, I have a post all about web frameworks!

A couple quick notes before we begin
  • To make this tutorial a little more succinct, some code examples have ... before or after them, which means that some code was omitted.
  • I use Git diffs in some places to show lines of code that will change, so if you copy and paste, you need to delete the + at the beginning of the line.
  • I have full CodePens with the completed versions of each section -- so you can use those to catch-up!
  • More advanced concepts that aren't essential for the tutorial are in blockquotes, these are mostly just facts that I think are interesting!
Set Up

If you are creating a production React application, you will want to use a build tool, like Webpack, to bundle your code since React utilizes some patterns that won't work by default in the browser. Create React App is super helpful for these purposes, since it does most of the configuration for you!

For now, since we want to get up and running super quickly so we can write actual React code, we will be using the React CDN, which is only for development purposes! We will also use the Babel CDN so that we can use some non-standard JavaScript features (we'll talk more about that later!).

<script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.25.0/babel.min.js"></script>

I also made a Codepen template that you can use!

In a full React project, I would split my components into different files, but again, for learning purposes, we will combine our JavaScript into one file for now.

Getting Started

I wanted to start off this tutorial with a React "Hello World" -- it is tradition after all! Then we'll move to the slightly more complex status example.

In our HTML file, let's add just one element -- a div with an id on it. By convention, you will normally see that div have an id "root" on it since it will be the root of our React application!

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

If you're writing the code in the CodePen template, you can write this JavaScript directly in the js section. If you are instead writing this on your computer, you will have to add a script tag with the type text/jsx, so:

<script type="text/jsx"></script>

Now, let's get to our React code!

class HelloWorld extends React.Component {
  render() {
    // Tells React what HTML code to render
    return <h1>Hello World</h1>
  }
}

// Tells React to attach the HelloWorld component to the 'root' HTML div
ReactDOM.render(<HelloWorld />, document.getElementById("root"))

All that happens is that "Hello World" is displayed as an H1 on the page!

Let's walk through what's going on here.

First, we are using an ES6 class that inherits from the React.Component class. This is a pattern that we will use for most of our React components.

Next, we have a method in our class -- and its a special method called render. React looks for the render method to decide what to render on the page! The name makes sense. Whatever is returned from that render method, will be rendered by that component.

In this case, we are returning an H1 with the text of "Hello World" -- this is exactly what would be in the HTML file normally.

Finally, we have:

ReactDOM.render(<HelloWorld />, document.getElementById("root"))

We are using the ReactDOM functionality to attach our react component to the DOM.

React utilizes something called the virtual DOM which is a virtual representation of the DOM that you would normally interact with in Vanilla JavaScript or JQuery. This reactDOM.render renders this virtual DOM to the actual DOM. Behind the scenes, React does a lot of work to efficiently edit and re-render the DOM when something on the interface needs to change.
Our component, <HelloWorld />, looks like an HTML tag! This syntax is part of JSX which is an extension of JavaScript. You can't natively use it in the browser. Remember how we're using Babel for our JavaScript? Babel will transpile (or convert) our JSX into regular JavaScript so the browser can understand it.
JSX is actually optional in React, but you'll see it used in the vast majority of cases!
Then, we are using JavaScript's built-in document.getElementById to grab our root element we created in our HTML.

All in all, in this ReactDOM.render statement, we are attaching our HelloWorld component to our div that we created in our HTML file.

Starter Code

Okay -- now that we've done a "Hello World," we can get started with our Facebook component.

First, I want you to play around with this demo. We'll be working on this throughout the rest of the tutorial. Feel free to look at the code too, but don't worry about not understanding it! That's what the rest of the tutorial is for!

Let's start off by "hard coding" the HTML for the widget:

<div class="content">
  <div class="col-6 offset-3">
    <div class="card">
      <div class="card-block">
        <div class="row">
          <div class="col-2">
            <img src="https://zen-of-programming.com/react-intro/selfiesquare.jpg" class="profile-pic">
          </div>
          <div class="col-10 profile-row">
            <div class="row">
              <a href="#">The Zen of Programming</a>
            </div>
            <div class="row">
              <small class="post-time">10 mins</small>
            </div>
          </div>
        </div>
        <p>Hello World!</p>
        <div>
          <span class="fa-stack fa-sm">
            <i class="fa fa-circle fa-stack-2x blue-icon"></i>
            <i class="fa fa-thumbs-up fa-stack-1x fa-inverse"></i>
          </span>
        </div>
        <div>
          <hr class="remove-margin">
          <div>
            <button type="button" class="btn no-outline btn-secondary">
              <i class="fa fa-thumbs-o-up fa-4 align-middle" aria-hidden="true"></i>
              &nbsp;
              <span class="align-middle">Like</span>
            </button>
          </div>
        </div>
      </div>
      <div class="card-footer text-muted">
        <textarea class="form-control" placeholder="Write a comment..."></textarea>
        <small>120 Remaining</small>
      </div>
    </div>
  </div>
</div>

With some added CSS, this looks like the following:

Here's a Codepen with the full starter code.

For the sake of this tutorial, we will be creating four components: a Status component which will be the parent, a Like component that will encompass the liking logic, and the Comment component which will contain the logic for typing in a comment. The Like component will also have a child LikeIcon that will show up or be hidden when you toggle the like button.

Component Architecture

Let's go ahead and divide the HTML code that we've written into those components.

We'll start with the shell of a component, and we'll render it as well to make sure it's working!

class Status extends React.Component {
  render() {
    return (
      <div className="col-6 offset-3">
        <div className="card">
          <div className="card-block">
            <div className="row">
              <div className="col-10 profile-row">
                <div className="row">
                  <a href="#">The Zen of Programming</a>
                </div>
                <div class="row">
                  <small className="post-time">10 mins</small>
                </div>
              </div>
            </div>
          </div>
          <p>Hello world!</p>
          <div className="card-footer text-muted" />
        </div>
      </div>
    )
  }
}

ReactDOM.render(<Status />, document.getElementById("root"))

One interesting note about the above, is that we had to change "class" attributes to "className". Class already means something in JavaScript -- its for es6 classes! Some attributes are named differently in JSX than in HTML.
We can also delete the content of our HTML, leaving just an element with the ID root -- the parent "content" div is just for styling!

<body>
  <div class="content">
    <div id="root"></div>
  </div>
</body>

Here's the HTML that is going to go in the Status component. Notice, some of the original HTML isn't there yet -- it's going to go into our subcomponents instead!

Let's create a second component, and then we'll include it in our Status component.

class Comment extends React.Component {
  render() {
    return (
      <div>
        <textarea className="form-control" placeholder="Write a comment..." />
        <small>140 Remaining</small>
      </div>
    )
  }
}

Here's the component for our comment. It just has our textarea to type in, and the text with how many characters we have remaining. Notice that both are wrapped in a div -- this is because React requires us to wrap all the contents of a component within one HTML tag -- if we didn't have the parent div we'd be returning a textarea and a small tag.

So, now we need to include this component within our Status component since it will be our subcomponent. We can do so using that same JSX syntax we used to render the Status component!

class Status extends React.Component {
  render() {
    return (
      <div className="col-6 offset-3">
        <div className="card">
          <div className="card-block">
            <div className="row">
              <div className="col-10 profile-row">
                <div className="row">
                  <a href="#">The Zen of Programming</a>
                </div>
                <div className="row">
                  <small className="post-time">10 mins</small>
                </div>
              </div>
            </div>
          </div>
          <div className="card-footer text-muted">
+           <Comment />
          </div>
        </div>
      </div>
    )
  }
}

Okay, now we just need to do the same for our likes!

class LikeIcon extends React.Component {
  render() {
    return (
      <div>
        <span className="fa-stack fa-sm">
          <i className="fa fa-circle fa-stack-2x blue-icon" />
          <i className="fa fa-thumbs-up fa-stack-1x fa-inverse" />
        </span>
      </div>
    )
  }
}

class Like extends React.Component {
  render() {
    return (
      <div>
        {/* Include the LikeIcon subcomponent within the Like component*/}
        <LikeIcon />
        <hr />
        <div>
          <button type="button">
            <i
              className="fa fa-thumbs-o-up fa-4 align-middle"
              aria-hidden="true"
            />
            &nbsp;
            <span className="align-middle">Like</span>
          </button>
        </div>
      </div>
    )
  }
}

Then we need to include it in our original Status component!

class Status extends React.Component {
  render() {
    return (
      <div className="col-6 offset-3">
        <div className="card">
          <div className="card-block">
            <div className="row">
              <div className="col-10 profile-row">
                <div className="row">
                  <a href="#">The Zen of Programming</a>
                </div>
                <div className="row">
                  <small className="post-time">10 mins</small>
                </div>
              </div>
            </div>
+           <Like />
          </div>
          <div className="card-footer text-muted">
            <Comment />
          </div>
        </div>
      </div>
    )
  }
}

Cool, now we have React-ified our original HTML, but it still doesn't do anything! Let's start fixing that!

All in all, the code from this section will look like this CodePen!

State and Props

We have two different user interactions that we want to implement:

  • We want the like icon to show up only if the like button is pressed
  • We want the number of characters remaining to decrease as the person

Let's start working on these!

Props

Imagine that we wanted our comment box to allow for a different number of letters in different places. On a status, for example, we want a user to be allowed to write a 200 letter long response. On a picture, however, we only want them to be able to write a 100 character response.

React allows us to pass props (short for properties) from the PictureStatus component and the Status component to specify how many letters we want to allow in our response, rather than having two different comment components.

The syntax for props looks like the following:

<Comment maxLetters={20} />
<Comment text='hello world' />
<Comment show={false} />

var test = 'hello world'
<Comment text={test} />

The props look like HTML attributes! If you are passing a string via props, you don't need the brackets, but any other data type or a variable needs to be within the brackets!

Then, within our component, we can use our props:

console.log(this.props.maxLetters)

They are bundled together in the props attribute of the instance so they can be accessed with this.props.myPropName.

So, let's change the hardcoded 140 characters to be easily changeable outside the component!

First, we'll change where we instantiate the Comment component within the Status component (note some code is omitted!):

class Status extends React.Component {
        ...
          <div className="card-footer text-muted">
+            <Comment maxLetters={280} />
          </div>
        </div>
      </div>
    )
  }
}

Then we'll change the hardcoded 140 character limit in the Comment component.

class Comment extends React.Component {
  ...
        <div>
        <textarea className="form-control" placeholder="Write a comment..." />
+       <small>{this.props.maxLetters} Remaining</small>
      </div>
  ...
}

State

The props that we pass from component to component will never change within the child component -- they can change within the parent but not within the child. But -- a lot of the time we will have attributes that we will want to change within the life of a component. For example, we want to keep a tally of how many characters the user has typed into the textarea, and we want to keep track of whether the status has been "liked" or not. We will store those attributes that we want to change within the component in its state.

You'll notice a lot of immutability within React -- it is highly influenced by the functional paradigm, so side effects are also discouraged.
We want this state to be created whenever we create a new instance of a component, so we will use the ES6 class constructor to create it. If you want a quick refresh on ES6 classes MDN is a great resource!

State is going to be an object with any key-value pairs that we want to include. In this case, we want a characterCount of how many characters the user has typed. We'll set that to zero for now!

class Comment extends React.Component {
  constructor () {
    super()
    this.state = {
      characterCount: 0
    }
  }
  ...

Now let's subtract that from the maxLetters prop, so we always know how many characters we have remaining!

<small>{this.props.maxLetters - this.state.characterCount} Remaining</small>

If you increase the characterCount, the characters remaining display decreases!

But -- nothing happens when you type! We're never changing the value of characterCount. We need to add an event handler to the textarea so that we change the characterCount when the user types!

Event Handlers

When you've written JavaScript in the past, you've probably written event handlers to interact with user input. We are going to do the same in React, the syntax is just going to be a little bit different.

We are going to add a onChange handler to our textarea. Inside of it, we will place a reference to an event handling method that will run every time the user types in the textarea.

  <textarea className="form-control" placeholder="Write a comment..." onChange={this.handleChange}/>

Now we need to create a handleChange method!

class Comment extends React.Component {
  constructor () {
    super()
    this.state = {
      characterCount: 0
    }
  }

  handleChange (event) {
    console.log(event.target.value)
  }
...

Right now, we're just console.log-ing the event.target.value -- this will work the same way as it does in React-less JavaScript (though if you dive a little deeper, the event object is a little bit different). If you look at that console, we are printing out what we are typing in the textbox!

Now we need to update the characterCount attribute in state. In React, we never directly modify state, so we can't do something like this: this.state.characterCount = event.target.value.length. We instead need to use the this.setState method.

  handleChange (event) {
    this.setState({
      characterCount: event.target.value.length
    })
  }

But! You get an error -- "Uncaught TypeError: this.setState is not a function". This error is telling us that need to preserve the context of the es6 class within the event handler. We can do this by binding this to the method in the constructor! If you want to read more about this, here's a good article!

class Comment extends React.Component {
  constructor () {
    super()    
    this.handleChange = this.handleChange.bind(this)
...

Okay! We're almost there! We just need to add the ability to toggle the like showing up!

We need to add a constructor to our Like component. In that constructor, we need to instantiate the component's state. The thing that will change within the lifecycle of the component is whether or not the status has been liked.

class Like extends React.Component {
  constructor() {
    super()

    this.state = {
      liked: false
    }
  }
  ...

Now we need to add an event handler to change whether or not the status has been liked!

class Like extends React.Component {
  constructor() {
    super()

    this.state = {
      liked: false
    }

    this.toggleLike = this.toggleLike.bind(this)
  }

  toggleLike () {
    this.setState(previousState => ({
      liked: !previousState.liked
    }))
  }
...

The difference here is that the callback function that this.setState receives a parameter -- previousState. As you can probably guess from the name of the parameter, this is the value of state before this.setState is called. setState is asynchronous, so we can't depend on using this.state.liked within it.

Now, we need to:

a) call the event handler whenever the user clicks on the like button:

b) only show the LikeIcon when liked is true

  render() {
    return (
      <div>
        {/* Use boolean logic to only render the LikeIcon if liked is true */}
+       {this.state.liked && <LikeIcon />}
        <hr />
        <div>
+          <button type="button" className="btn no-outline btn-secondary" onClick={this.toggleLike}>
            <i
              className="fa fa-thumbs-o-up fa-4 align-middle"
              aria-hidden="true"
            />
            &nbsp;
            <span className="align-middle">Like</span>
          </button>
        </div>
      </div>
    )
  }

Awesome! Now all of our functionality is in place!

Bonus: Functional components

If you feel like you're in over your head already, feel free to skip this part, but I wanted to make one more quick refactor to this project. If we create components that don't have state associated with them (which we call stateless components), we can make our components into functions instead of ES6 classes.

In that case, our LikeIcon could look something like this:

const LikeIcon = () => {
  return (
    <div>
      <span className="fa-stack fa-sm">
        <i className="fa fa-circle fa-stack-2x blue-icon" />
        <i className="fa fa-thumbs-up fa-stack-1x fa-inverse" />
      </span>
    </div>
  )
}

We just return the UI of the component instead of using the render method!

Here is a CodePen that implements this refactor!

Cheat Sheet

I love cheatsheets, so I made one with the content from this post!

You can also download it as a PDF here!

Next Steps

To recap, we talked about the component architecture, the basic React syntax and JSX, state and props, event handlers, and functional components.

If you would like to view all the CodePens from this tutorial, here is a collection!

If you would like to try to extend the code from this tutorial, I would recommend changing likes to reactions or creating a photo component that reuses some of the components that we made!

JavaScript developers should you be using Web Workers?

JavaScript developers should you be using Web Workers?

Do you think JavaScript developers should be making more use of Web Workers to shift execution off of the main thread?

Originally published by David Gilbertson at https://medium.com

So, Web Workers. Those wonderful little critters that allow us to execute JavaScript off the main thread.

Also known as “no, you’re thinking of Service Workers”.

Photo by Caleb Jones on Unsplash

Before I get into the meat of the article, please sit for a lesson in how computers work:

Understood? Good.

For the red/green colourblind, let me explain. While a CPU is doing one thing, it can’t be doing another thing, which means you can’t sort a big array while a user scrolls the screen.

This is bad, if you have a big array and users with fingers.

Enter, Web Workers. These split open the atomic concept of a ‘CPU’ and allow us to think in terms of threads. We can use one thread to handle user-facing work like touch events and rendering the UI, and different threads to carry out all other work.

Check that out, the main thread is green the whole way through, ready to receive and respond to the gentle caress of a user.

You’re excited (I can tell), if we only have UI code on the main thread and all other code can go in a worker, things are going to be amazing (said the way Oprah would say it).

But cool your jets for just a moment, because websites are mostly about the UI — it’s why we have screens. And a lot of a user’s interactions with your site will be tapping on the screen, waiting for a response, reading, tapping, looking, reading, and so on.

So we can’t just say “here’s some JS that takes 20ms to run, chuck it on a thread”, we must think about where that execution time exists in the user’s world of tap, read, look, read, tap…

I like to boil this down to one specific question:

Is the user waiting anyway?

Imagine we have created some sort of git-repository-hosting website that shows all sorts of things about a repository. We have a cool feature called ‘issues’. A user can even click an ‘issues’ tab in our website to see a list of all issues relating to the repository. Groundbreaking!

When our users click this issues tab, the site is going to fetch the issue data, process it in some way — perhaps sort, or format dates, or work out which icon to show — then render the UI.

Inside the user’s computer, that’ll look exactly like this.

Look at that processing stage, locking up the main thread even though it has nothing to do with the UI! That’s terrible, in theory.

But think about what the human is actually doing at this point. They’re waiting for the common trio of network/process/render; just sittin’ around with less to do than the Bolivian Navy.

Because we care about our users, we show a loading indicator to let them know we’ve received their request and are working on it — putting the human in a ‘waiting’ state. Let’s add that to the diagram.

Now that we have a human in the picture, we can mix in a Web Worker and think about the impact it will have on their life:

Hmmm.

First thing to note is that we’re not doing anything in parallel. We need the data from the network before we process it, and we need to process the data before we can render the UI. The elapsed time doesn’t change.

(BTW, the time involved in moving data to a Web Worker and back is negligible: 1ms per 100 KB is a decent rule of thumb.)

So we can move work off the main thread and have a page that is responsive during that time, but to what end? If our user is sitting there looking at a spinner for 600ms, have we enriched their experience by having a responsive screen for the middle third?

No.

I’ve fudged these diagrams a little bit to make them the gorgeous specimens of graphic design that they are, but they’re not really to scale.

When responding to a user request, you’ll find that the network and DOM-manipulating part of any given task take much, much longer than the pure-JS data processing part.

I saw an article recently making the case that updating a Redux store was a good candidate for Web Workers because it’s not UI work (and non-UI work doesn’t belong on the main thread).

Chucking the data processing over to a worker thread sounds sensible, but the idea struck me as a little, umm, academic.

First, let’s split instances of ‘updating a store’ into two categories:

  1. Updating a store in response to a user interaction, then updating the UI in response to the data change
  2. Not that first one

If the first scenario, a user taps a button on the screen — perhaps to change the sort order of a list. The store updates, and this results in a re-rendering of the DOM (since that’s the point of a store).

Let me just delete one thing from the previous diagram:

In my experience, it is rare that the store-updating step goes beyond a few dozen milliseconds, and is generally followed by ten times that in DOM updating, layout, and paint. If I’ve got a site that’s taking longer than this, I’d be asking questions about why I have so much data in the browser and so much DOM, rather than on which thread I should do my processing.

So the question we’re faced with is the same one from above: the user tapped something on the screen, we’re going to work on that request for hopefully less than a second, why would we want to make the screen responsive during that time?

OK what about the second scenario, where a store update isn’t in response to a user interaction? Performing an auto-save, for example — there’s nothing more annoying than an app becoming unresponsive doing something you didn’t ask it to do.

Actually there’s heaps of things more annoying than that. Teens, for example.

Anyhoo, if you’re doing an auto-save and taking 100ms to process data client-side before sending it off to a server, then you should absolutely use a Web Worker.

In fact, any ‘background’ task that the user hasn’t asked for, or isn’t waiting for, is a good candidate for moving to a Web Worker.

The matter of value

Complexity is expensive, and implementing Web Workers ain’t cheap.

If you’re using a bundler — and you are — you’ll have a lot of reading to do, and probably npm packages to install. If you’ve got a create-react-app app, prepare to eject (and put aside two days twice a year to update 30 different packages when the next version of Babel/Redux/React/ESLint comes out).

Also, if you want to share anything fancier than plain data between a worker and the main thread you’ve got some more reading to do (comlink is your friend).

What I’m getting at is this: if the benefit is real, but minimal, then you’ve gotta ask if there’s something else you could spend a day or two on with a greater benefit to your users.

This thinking is true of everything, of course, but I’ve found that Web Workers have a particularly poor benefit-to-effort ratio.

Hey David, why you hate Web Workers so bad?

Good question.

This is a doweling jig:

I own a doweling jig. I love my doweling jig. If I need to drill a hole into the end of a piece of wood and ensure that it’s perfectly perpendicular to the surface, I use my doweling jig.

But I don’t use it to eat breakfast. For that I use a spoon.

Four years ago I was working on some fancy animations. They looked slick on a fast device, but janky on a slow one. So I wrote fireball-js, which executes a rudimentary performance benchmark on the user’s device and returns a score, allowing me to run my animations only on devices that would render them smoothly.

Where’s the best spot to run some CPU intensive code that the user didn’t request? On a different thread, of course. A Web Worker was the correct tool for the job.

Fast forward to 2019 and you’ll find me writing a routing algorithm for a mapping application. This requires parsing a big fat GeoJSON map into a collection of nodes and edges, to be used when a user asks for directions. The processing isn’t in response to a user request and the user isn’t waiting on it. And so, a Web Worker is the correct tool for the job.

It was only when doing this that it dawned on me: in the intervening quartet of years, I have seen exactly zero other instances where Web Workers would have improved the user experience.

Contrast this with a recent resurgence in Web Worker wonderment, and combine that contrast with the fact that I couldn’t think of anything else to write about, then concatenate that combined contrast with my contrarian character and you’ve got yourself a blog post telling you that maybe Web Workers are a teeny-tiny bit overhyped.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

An Introduction to Web Workers

JavaScript Web Workers: A Beginner’s Guide

Using Web Workers to Real-time Processing

How to use Web Workers in Angular app

Using Web Workers with Angular CLI