How to solve a Problem with React

How to solve a Problem with React

In this Guide you learn how to plan your React application and create composable React components. Let’s begin.

In this Guide you learn how to plan your React application and create composable React components. Let’s begin.

Solving a problem using React

Before you start writing code for your web application, you need to think about the problems that your web application is going to solve. It’s very important to understand that defining the problem as clearly and as early as possible is the most important step toward a successful solution—a useful web application. If you fail to define your problem early in your development process, or you define it inaccurately, then later on you’ll have to stop, rethink about what you’re doing, throw away a piece of the code that you have already written, and write a new one. This is a wasteful approach, and as a professional software developer your time is very valuable, not only to you but also to your organization, so it’s in your best interests to invest it wisely. Earlier in this book, I stressed on the fact that one of the benefits of using React is code reuse, which means that you’ll be able to do more in less time. However, before we take a look at the React code, let’s first discuss the problem, keeping React in mind.

We’ll be building Snapterest—a web application that receives tweets from a Snapkite Engine server in a real-time manner and displays them one at a time to a user. We don’t actually know when Snapterest will receive a new tweet, but when it does, it will display that new tweet for at least 1.5 seconds so that the user has enough time to take a look at it and click on it. Clicking on a tweet will add it to an existing collection of tweets or create a new one. Finally, users will be able to export their collection to an **HTML **markup code.

This is a very high-level description of what we’re going to build. Let’s break it down into a list of smaller tasks:

  1. Receive tweets from the Snapkite Engine server in real time.
  2. Display one tweet at a time for at least 1.5 seconds.
  3. Add tweets to a collection on a user click event.
  4. Display a list of tweets in a collection.
  5. Create an HTML markup code for a collection and export it.
  6. Remove tweets from a collection on a user click event.

Now that we’ve identified a potential solution for each individual task, let’s think about how are we going to put them together and create a fully functional web application.

There are two ways to build composable React applications:

  • You can start by building individual React components and then compose them together into higher-level React components, moving up the component hierarchy.
  • You can start from the topmost React element and then implement its child components, moving down the component hierarchy.

The second strategy has the advantage of seeing and understanding the big picture of your application’s architecture. I think it’s important to understand how everything fits together before we can think of how individual pieces of functionality are implemented.

Planning your React application

There are two simple guidelines we need to follow when planning your React application:

  • Each React component should represent a single user interface element in your web application. It should encapsulate the smallest element possible that can potentially be reused.
  • Multiple React components should be composed into a single React component. Ultimately, your entire user interface should be encapsulated in one React component.

Diagram of our React components hierarchy

We’ll begin with our topmost React component, Application. It will encapsulate our entire React application, and it will have two child components: the Stream and Collection components. The Stream component will be responsible for connecting to a stream of tweets, and receiving and displaying the latest tweet. The Stream component will have two child components: StreamTweet and Header. The StreamTweet component will be responsible for displaying the latest tweet. It will be composed of the Header and Tweet components. A Header component will render a header. It will have no child components. A Tweet component will render an image from a tweet. Notice how we’re planning to reuse the Header component twice already.

The Collection component will be responsible for displaying the collection controls and a list of tweets. It will have two child components: CollectionControls and TweetList. The CollectionControls will have two child components: the CollectionRenameForm component that will render a form to rename a collection, and the CollectionExportForm component that will render a form to export a collection to a service called CodePen, which is an HTML, CSS, and JavaScript playground website. You can learn more about CodePen at http://codepen.io. As you might have noticed, we’ll reuse the Header and Button components in the CollectionRenameForm and CollectionControls components. Our TweetList component will render a list of tweets. Each tweet will be rendered by a Tweet component. We’ll be reusing the Header component once again in our Collection component. In fact, in total, we’ll be reusing the Header component five times. , we should keep as many React components stateless as possible. So only 5 out of 11 components will store the state, which are:

Creating a container React** component**

Let’s start by editing our application’s main JavaScript file. Replace the contents of the ~/snapterest/source/app.js file with the following code snippet:

var React = require('react');
var ReactDOM = require('react-dom');
var Application = require('./components/Application.react');

ReactDOM.render(<Application ></Application>, document.getElementById('react-application'));

There are only four lines of code in this file, and as you can guess, they provide document.getElementById('react-application') as a deployment target for the <Application ></Application> component and render <Application ></Application> to the DOM. The whole user interface for our web application will be encapsulated in one React component, Application.

Next, navigate to ~/snapterest/source/components/ and create the Application.react.js file inside this directory. All of our React components will have their filenames ending with react.js. This convention allows us to easily distinguish between React and non-React source JavaScript files.

Let’s take a look at the contents of the Application.react.js file:

var React = require('react');
var Stream = require('./Stream.react');
var Collection = require('./Collection.react');

var Application = React.createClass({

  getInitialState: function () {
    return {
      collectionTweets: {}
    };
  },

  addTweetToCollection: function (tweet) {
    var collectionTweets = this.state.collectionTweets;

    collectionTweets[tweet.id] = tweet;

    this.setState({
      collectionTweets: collectionTweets
    });
  },

  removeTweetFromCollection: function (tweet) {
    var collectionTweets = this.state.collectionTweets;

    delete collectionTweets[tweet.id];

    this.setState({
      collectionTweets: collectionTweets
    });
  },

  removeAllTweetsFromCollection: function () {
    this.setState({
      collectionTweets: {}
    });
  },

  render: function () {
    return (
      <div className="container-fluid">

        <div className="row">
          <div className="col-md-4 text-center">

            <Stream onAddTweetToCollection={this.addTweetToCollection} ></Stream>

          </div>
          <div className="col-md-8">

            <Collection
              tweets={this.state.collectionTweets}
              onRemoveTweetFromCollection={this.removeTweetFromCollection}
              onRemoveAllTweetsFromCollection={this.removeAllTweetsFromCollection} />

          </div>
        </div>

      </div>
    );
  }
});

module.exports = Application;

This component has significantly more code than our app.js file, but this code can be easily divided into three logical parts:

  • Importing dependency modules
  • Defining React components
  • Exporting a React component as a module

You will see this logical separation in most of our React components because they are wrapped into the CommonJS module pattern that allows us to easily require them with Browserify. In fact, the first and the third parts of this source file are related to how CommonJS works and have nothing to do with how React works. The purpose of using this module pattern is to break our application into modules that can be easily reused. Because the React component and CommonJS module pattern both encapsulate the code and make it portable, they naturally work great together. So, we end up encapsulating our user interface logic in a React component and then encapsulate that React component in the CommonJS module. It then can be used in any other module that wants to reuse this encapsulated React component.

In our first logical part of the Application.react.js file, we’re importing the dependency modules using the require() function:

var React = require('react');
var Stream = require('./Stream.react');
var Collection = require('./Collection.react');

Our Application component will have two child components that we need to import:

  • The Stream component will render a stream section of our user interface
  • The Collection component will render a collection section of our user interface

We also need to import the React library as another module. Notice that this code is still part of the CommonJS module pattern, not React.

The second logical part of the Application.react.js file creates the React Application component with the following methods:

  • getInitialState()
  • addTweetToCollection()
  • removeTweetFromCollection()
  • removeAllTweetsFromCollection()
  • render()

Only the getInitialState() and render() methods are part of the React API. All the other methods are part of our application logic that this component encapsulates. We’ll take a closer look at each of them right after we discuss what this component renders inside its render() function:

render: function () {
  return (
    <div className="container-fluid">

      <div className="row">
        <div className="col-md-4 text-center">

          <Stream onAddTweetToCollection={this.addTweetToCollection} ></Stream>

        </div>
        <div className="col-md-8">

          <Collection
            tweets={this.state.collectionTweets}
           onRemoveTweetFromCollection={this.removeTweetFromCollection}
       onRemoveAllTweetsFromCollection={this.removeAllTweetsFromCollection} />

        </div>
      </div>

    </div>
  );
}

As you can see, it defines the layout of our web page using the Bootstrap framework. If you’re not familiar with Bootstrap, I strongly recommend that you visit http://getbootstrap.com and read the documentation. Learning this framework will empower you to prototype user interfaces in a fast and easy way. Even if you don’t know Bootstrap, it’s quite easy to understand what’s going on. We’re dividing our web page into two columns: a smaller one and a larger one. The smaller one contains our Stream React component and the larger one contains our Collection component. You can imagine that our web page is divided into two unequal parts and both of them contain the React components.

This is how we’re using our Stream component:

<Stream onAddTweetToCollection={this.addTweetToCollection} ></Stream>

The Stream component has an onAddTweetToCollection property, and our Application component passes its own addTweetToCollection() function as a value for this property. addTweetToCollection()adds a tweet to a collection. It’s one of the custom methods that we define in our Application component, and we can refer to it using this keyword.

Let’s take a look at what the addTweetToCollection() function does:

addTweetToCollection: function (tweet) {
  var collectionTweets = this.state.collectionTweets;

  collectionTweets[tweet.id] = tweet;

  this.setState({
    collectionTweets: collectionTweets
  });
},

This function references CollectionTweets that are stored in the current state, adds a new tweet to a collectionTweets object, and updates the state by calling the setState() function. A new tweet is passed as an argument when the addTweetToCollection() function is called inside a Stream component. This is an example of how a child component can update its parent component’s state.

This an important mechanism in React and it works as follows:

  1. A parent component passes a callback function as a property to its child component. A child component can access this callback function via the this.props variable.
  2. Whenever a child component wants to update the parent component’s state, it calls that callback function and passes all the necessary data to a new parent component’s state.
  3. A parent component updates its state, and as you already know, this state updates and triggers the render() function that re-renders all the child components, as necessary.

This is how a child component interacts with a parent component. This interaction allows a child component to delegate the application’s state management to its parent component, and it is only concerned with how to render itself. Now, when you’ve learned this pattern, you will be using it again and again because most of your React components should stay stateless. Only a few parent components should store and manage your application’s state. This best practice allows us to logically group React components by the two different concerns that they address:

  • Manage the application’s state and render
  • Only render and delegate the application’s state management to a parent component

Our Application component has a second child component, Collection:

<Collection
  tweets={this.state.collectionTweets}
  onRemoveTweetFromCollection={this.removeTweetFromCollection}
onRemoveAllTweetsFromCollection={this.removeAllTweetsFromCollection} />

This component has a number of properties:

  • tweets: This refers to our current collection of tweets
  • onRemoveTweetFromCollection: This refers to a function that removes a particular tweet from our collection
  • onRemoveAllTweetsFromCollection: This refers to a function that removes all the tweets from our collection

You can see that the Collection component’s properties are only concerned about how to:

  • Access the application’s state
  • Mutate the application’s state

As you can guess, the onRemoveTweetFromCollection and onRemoveAllTweetsFromCollection functions allow the Collection component to mutate the Application component’s state. On the other hand, the tweets property propagates the Application component’s state to the Collection component so that it can gain a read-only access to that state.

Can you recognize the single direction of data flow between the Application and Collection components? Here’s how it works:

  1. The collectionTweets data is initialized in the Application component’s getInitialState() method.
  2. The collectionTweets data is passed to the Collection component as the tweets property.
  3. The Collection component calls the removeTweetFromCollection and removeAllTweetsFromCollection functions that update the collectionTweets data in the Application component, and the cycle starts again.

Notice that the Collection component cannot directly mutate the Application component’s state. The Collection component has read-only access to that state via this.props object, and the only way to update the parent component’s state is to call the callback functions that are passed by the parent component. In the Collection component, these callback functions are this.props.onRemoveTweetFromCollection and this.props.onRemoveAllTweetsFromCollection.

This simple mental model of how data flows in our React component hierarchy will help us increase the number of components we use, without increasing the complexity of how our user interface works. For example, it can have 10 levels of nested React components, as follows:

If Component G wants to mutate the state of root Component A, it would do it in the exact same way that Component B, or Component F, or any other component in this hierarchy would. However, in React, you shouldn’t pass data from Component A directly to Component G. Instead, you should first pass it to Component B, then to Component C, then to Component D, and so on until you finally reach Component G. Component B to Component F will have to carry some “transit” properties that are actually only meant for Component G. This might look like a waste of time, but this design makes it easy for us to debug our application and be able to reason out how it works. There are always strategies to optimize your application’s architecture. One of them is to use Flux, which we’ll discuss later in this book.

Before we finish discussing our Application component, let’s take a look at the two methods that mutate its state:

removeAllTweetsFromCollection: function () {
  this.setState({
    collectionTweets: {}
  });
},

The removeTweetFromCollection() method removes a tweet from a collection of tweets that we store in the Application component’s state. It takes the current collectionTweets object from the component’s state, deletes a tweet with a given ID from that object, and updates the component’s state with an updated collectionTweets object.

On the other hand, the removeAllTweetsFromCollection() method removes all the tweets from the component’s state:

removeAllTweetsFromCollection: function () {
  this.setState({
    collectionTweets: {}
  });
},

Both of these methods are called from a child’s Collection component because that component has no other way to mutate the Application component’s state.

This function references CollectionTweets that are stored in the current state, adds a new tweet to a collectionTweets object, and updates the state by calling the setState() function. A new tweet is passed as an argument when the addTweetToCollection() function is called inside a Stream component. This is an example of how a child component can update its parent component’s state.

This an important mechanism in React and it works as follows:

  1. A parent component passes a callback function as a property to its child component. A child component can access this callback function via the this.props variable.
  2. Whenever a child component wants to update the parent component’s state, it calls that callback function and passes all the necessary data to a new parent component’s state.
  3. A parent component updates its state, and as you already know, this state updates and triggers the render() function that re-renders all the child components, as necessary.

This is how a child component interacts with a parent component. This interaction allows a child component to delegate the application’s state management to its parent component, and it is only concerned with how to render itself. Now, when you’ve learned this pattern, you will be using it again and again because most of your React components should stay stateless. Only a few parent components should store and manage your application’s state. This best practice allows us to logically group React components by the two different concerns that they address:

  • Manage the application’s state and render
  • Only render and delegate the application’s state management to a parent component

Our Application component has a second child component, Collection:

<Collection
  tweets={this.state.collectionTweets}
  onRemoveTweetFromCollection={this.removeTweetFromCollection}
onRemoveAllTweetsFromCollection={this.removeAllTweetsFromCollection} />

This component has a number of properties:

  • tweets: This refers to our current collection of tweets
  • onRemoveTweetFromCollection: This refers to a function that removes a particular tweet from our collection
  • onRemoveAllTweetsFromCollection: This refers to a function that removes all the tweets from our collection

You can see that the Collection component’s properties are only concerned about how to:

  • Access the application’s state
  • Mutate the application’s state

As you can guess, the onRemoveTweetFromCollection and onRemoveAllTweetsFromCollection functions allow the Collection component to mutate the Application component’s state. On the other hand, the tweets property propagates the Application component’s state to the Collection component so that it can gain a read-only access to that state.

Can you recognize the single direction of data flow between the Application and Collection components? Here’s how it works:

  1. The collectionTweets data is initialized in the Application component’s getInitialState() method.
  2. The collectionTweets data is passed to the Collection component as the tweets property.
  3. The Collection component calls the removeTweetFromCollection and removeAllTweetsFromCollection functions that update the collectionTweets data in the Application component, and the cycle starts again.

Notice that the Collection component cannot directly mutate the Application component’s state. The Collection component has read-only access to that state via this.props object, and the only way to update the parent component’s state is to call the callback functions that are passed by the parent component. In the Collection component, these callback functions are this.props.onRemoveTweetFromCollection and this.props.onRemoveAllTweetsFromCollection.

wrapping up

In this Guide, we learned how to solve a problem with React. We started by breaking down the problem into smaller individual problems and then discussed how we can address them using React. Then, we created a list of React components that we needed to implement. Finally, we created our first composable React component and learned how a parent component interacts with its child components. In the next Guide, we’ll implement our child components and learn about React’s lifecycle methods.

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