A Primer on the React Ecosystem: Part 2 of 3

Updates
2016.08.28: Updated The Code section with instructions to visit the dev server at http://localhost:8080 (without the /webpack-dev-server/ route). It appears the /webpack-dev-server/ route has some iframe security issue which hinders functionality.

2016.08.27: Moved the currentPreview variable out of the state object and made it part of App instead.

2016.08.04: Expanded Onward section to discuss what we want to do next with application state.

2016.08.02: First publication.

Part One Recap
In Part One, we set up a basic build environment using Webpack and Babel. We then test drove this environment by creating a simple React component. We also looked at the basics of component rendering and JSX, the React DSL used to specify React components.

In This Installment
In Part Two, we’ll enhance our build environment, then start building our Spotify client using React. Our aim is to let a user:

  • retrieve an artist’s albums,
  • retrieve an album’s tracks,
  • play a preview for a given track.

By the end of this post, you’ll have a greater understanding of React components and how to create and structure them to work together.

The Code
We’ll be picking up where we left off in Part One. The code for Part One is here. If you didn’t follow along previously and wish to do so now, then I suggest getting the code. Bear in mind you’ll want the code from the part01 branch. To clone it through Git, use this command:

Once the code is downloaded, run npm install in your project’s root directory to install the required dependencies.

The code for the end result of Part Two is here. To clone Part Two through Git use:

Run npm install, then npm run start to start the webpack dev server, then visit http://localhost:8080.

Linting
Before we begin creating the UI, we’ll enhance our build process with linting. Linting will help enforce some discipline in how we write our Javascript and JSX code and help keep things tidy. Whenever we save our work, the linter will scan our code and flag anything that violates rules we specify. For the job of linting, we’ll be using ESLint. The rules we’ll use will be from Airbnb. I like Airbnb’s ruleset as it’s fairly strict, but of course, you’re free to turn off any of them or add more if you wish.

Let’s start by installing the dependencies. Rather than installing each individually, take the block below and paste it into your package.json under devDependencies:

We’re doing this because, at the time of this writing, there are compatibility issues with ESLint 3.0 and the other ESLint packages. By specifying the exact version numbers, we can avoid these problems while they’re being sorted out.

Here’s a brief description of each package we’re installing:

Once you add the preceding lines, your devDependencies in package.json should look like this:

If the version numbers on your other packages are different, it’ll likely not cause a problem. If you wish, you can use the package.json file from Part Two directly.

Now run:

at your terminal to get the new packages installed locally.

Next, we need to incorporate linting into our Webpack build. Recall from Part One when we incorporated loaders into our Webpack build. Loaders are simply plugins which preprocess our files. We currently have loaders to copy our index.html file and translate our ES6 and JSX code to ES5. We’ll now add a loader for linting. Add the highlighted lines to the module object in  your webpack.config.js file:

Note how our other loaders are under a loaders object while our linting loader is going under a preLoaders object. Webpack provides three loader hooks: preLoaders, loaders, and postLoaders, which are executed in that order. It’s good practice to put linting in the preLoaders because if it fails, we’ll know about it first.

We’re also going to add this right above the modules object:

This reports all ESLint errors under a warning designation. This way, if our linter picks up something questionable, our dev server will still go ahead and build. Is that a good thing? Not necessarily. But given this is a tutorial, I didn’t want our environment to be so punishing and stop working just because of, let’s say, a missing space.

Your webpack.config.js file should now look like this:

The last step is to specify that we want to use the Airbnb ruleset. Create .eslintrc in your project’s root directory and populate it like so:

The .eslintrc file is where you specify the linting rules you want to enforce. In our case, since we installed the Airbnb ruleset earlier and don’t wish to add anymore, all we need to do is refer to it.

We just augmented our build process further with linting. Let’s test it out.

Start by deleting greeting.js from your src directory. We no longer need it.

Next, clear out index.js completely and put in this line.

The preceding line should be the only line in index.js. Save the file, then start your server with npm run start.

In your terminal, you should see output similar to this:

Each error message comprises four parts:

  1. Where in the file it’s occuring.
  2. The severity of the message.
  3. A description of the problem.
  4. The actual name of the ESLint rule.

Despite these errors, our app should still come up at:
http://localhost:8080/webpack-dev-server/

The only tell-tale is the status bar message at the top indicating there were Warnings while compiling:
warningsIf we had not specified that ESLint errors should be emitted as warnings, you would see the error messages in the terminal also appear in the browser like this:
errorsLet’s take a look at the errors. We can see that the Airbnb rules flag double-quoted strings, variables which are defined but never used, and files that aren’t ended with new-lines.

Modify index.js to look like this and save (remember to include the blank line at the end):

After changing the double quotes to single quotes, using foo in some manner, and ending the file with a newline, all linting errors should go away.

Turning off a rule is simple. Note the ESLint rule name, and override it in your .eslintrc file. So for example, suppose you wanted to turn off the rule for double-quoted strings. From the preceding message description, we note that the rule name is quotes, and then add the highlighted lines to .eslintrc:

Here we add a rules object and inside set the severity of the quotes rule to zero. If you restart your dev server now and use double-quoted strings again, you won’t see any errors. Personally, I like having that rule in place so I’m going to remove that override.

However, there are two rules I’m going to turn off, and that’s the arrow-body-style and no-param-reassign rules. The Airbnb rules flag situations where your arrow function can be more compact and forego having a body (arrow-body-style rule). But sometimes, I like being more explicit.

The rules also flag instances where passed-in parameters are being modified (no-param-reassign rule), but I do this for certain inline functions which affect styling such as in the Track component we’re going to build.

This is what my .eslintrc file looks like:

All linting warnings should now be gone. With that, we’re ready to build our app.

Breaking Down the UI
At the end of Part One, we created just a single component to test drive our setup. In practice, almost every React UI will be composed of multiple components. For example, in a weather app, you may have one component displaying the name of the place, another component displaying the current temperature, and another component displaying a graph of a five-day forecast.

Because of this, it’s good practice to break down a UI to its constituent components before starting development. There are no hard and fast rules on how to break down your UI, but like most things in programming, there are best-practices and guidelines. Here they are:

  1. Your component should do one thing. If it starts growing and taking on more responsibilities, it’s time to break it down further.
  2. Information should flow top-down. That is, parent components should pass data down to child components.

The second point may not make such sense at the moment, but will become clear as we start building.

Ok, so here’s the mock from Part One:
mockup

Taking inventory of this mock, we have:

  1. A search bar.
  2. A list of albums.
  3. One or more albums in the list of albums.
  4. A list of tracks.
  5. One or more tracks in the list of tracks.

So we have five distinct components (multiple albums are just instances of the same component. Same goes for tracks).

Using these distinctions to break down the UI leads to this:
respotify_breakdown

Here we have the:

  • Search Bar
  • Album List
  • Individual Albums
  • Track List
  • Individual Tracks

There are two things to note:

  1. Notice how instances of the Individual Albums component are inside the Album List component. And instances of the Individual Tracks component are inside the Track List component. When we see component B inside component A, we say component B is nested in component A. Another way to put it is component B is a child of component A.
  2. We actually have six components here. The sixth component is the yellow box in the breakdown, and it serves as the container for the entire app. It’s good practice to have a topmost component serving as the entry-point of the UI where you can initialize state and specify how child components should be arranged.

Visualized as a tree, our app now looks like this:
respotify_tree_visualization

Let’s start gaining some clarity on all this by building our app, starting with the App container. As we progress, there will be times when I jump back to a previous component to enhance it, or divert into an explanation because of a new feature not covered in previous parts. If you feel something wasn’t clear, post a comment or send me an email.

The App Container
Before we begin, make sure your src directory looks like this and that index.js is empty.

Now populate index.js as follows:

If you’re copying and pasting the code, then double-click on the codebox first. That’ll switch the codebox to ‘plain view’, which will eliminate extraneous spaces on blank lines and make it easier to lift out. You may need to add the final blank line yourself.

As usual, we start by importing the React and ReactDOM libraries at the top.

[Line 4] We create our App component class by extending the React.Component base class. This is the standard ES6-style for component classes. This is in contrast to how we created our component in Part One, where we used the ES5-style React.createClass method. From here on, we’ll be using ES6-style exclusively.

[Lines 5-11] Recall from Part One that every class-based React component must have a render method. Here, we define our render method to return some markup. In this case, just some text.

[Lines 14-17] We specify that we want an instance of the App component attached to a DOM element of id container. This element can be found in index.html. In other words, we want App to appear on our main page inside the container div.

You’re probably getting a complaint in the terminal from ESLint to the tune of this:

Don’t worry about it for now. We’re going to go over the different styles of component creation later on in this post, and this error will go away as we grow our App container.

Our app should now appear like this:respotify_app_container_02Great, we’ve just created our first component using ES6 syntax. Let’s move on to the search bar.

Search Bar
Create a components folder in the src directory. Inside the components folder, create SearchBar.jsx:

Let’s look at the new stuff here.

[Line 5] input is a React form component representing an input box.

[Line 9] We export our SearchBar component, making it the default export. In other words, when someone imports our SearchBar component, they’ll be able to reference it directly.

For the file, I’m using the .jsx extension and PascalCase to signal that this is a React component. This isn’t necessary and some prefer to signal this using only PascalCase (SearchBar.js) or even including react in the name (e.g. searchbar.react.js). Go with what you prefer as long as it’s consistent.

Let’s get the SearchBar component on screen.

Recall from the UI breakdown that the App component contains all the other components. In other words, all the other components are nested inside the App component. So what we need to do is nest the SearchBar component inside the App component by adding the highlighted lines to index.js:

[Line 3] We import our SearchBar component.

[Line 10] We instantiate the SearchBar component inside App‘s render method.

If you decided to follow my convention and use the .jsx extension, then something’s broken now. Your browser page is probably a sea of red looking like this:
searchbar_file_resolution_errors
When we import a component without specifying an extension, Webpack attempts to use a number of extensions to resolve it. What it does not try by default is .jsx. This is easily solved by modifying our webpack.config.js file with the highlighted lines:

[Line 29] We modify our eslint-loader to lint both .js and .jsx files.

[Line 40] We modify our babel-loader and hot-loader to handle both .js and .jsx files.

[Lines 46-48] We add an additional object to our config, instructing Webpack to resolve files with no extension, a .js extension, and a .jsx extension.

Restart your dev server. Webpack will now be able to find your SearchBar.jsx file and your screen should look like this:
searchbar_first_appearanceSo now we have a SearchBar component nested in our App container component. Assuming you haven’t turned off the prefer-stateless-function rule in ESLint, you’re probably seeing the same Component should be written as a pure function error for SearchBar. Keep going, we’ll be resolving that in a few minutes.

Now, we can type into the input box, but we also need to capture the value we input. To capture user input and actions, React offers a means to pass Event Handlers to components. These event handlers are merely callback functions the component will call in response to certain user actions. We pass in these functions by assigning them to certain component props.

For our purposes, we’re interested in the input component’s onChange prop. The event handler assigned to onChange will be called any time the value in the input box changes

Let’s start by adding and modifying the highlighted lines in SearchBar.jsx:

[Lines 4-6] This is our event handler to be called any time the value in the input box changes.

[Line 9] We modify the way we instantiate the input component by assigning our handleInputChange event handler to the onChange prop. handleInputChange will now be called each time the input box value changes.

If you open your console and start typing, you should see output similar to the following:
capture_onchangeAt this point, we’re handling and logging the input, but we’re still not capturing it; we’re not saving it somewhere so that we can use it for a search term. Before we do that, we need to go over state.

Initializing and Setting State
Recall from Part One that when we created our first component, we also passed it some state. To recap, we instantiated our greeting component like this:

We said, “Create a greeting component and pass it a piece of state called name with value ‘World'”.

Inside the greeting component, that state was then available through the props object:

This props object was immutable; the value of this.props.name could not be changed.

In a sense, the greeting component was “dumb”. It was simply told what to render. It had no say in it and couldn’t change anything. What we saw in Part One is how state can be passed to a component for consumption. Now, we’ll see how a component can manage its own state.

We need to capture the value in our SearchBar‘s input component since it dictates what we search for. In other words, what the user types is a piece of state we need to capture and keep updating.

The first step is to set SearchBar‘s state when it’s first created (i.e. to initialize it). When creating components ES6-style, we initialize a component’s state in its constructor. The second step is to update the state to the latest value of the input box each time the value changes.

Add the highlighted lines to SearchBar.jsx:

[Line 4] We declare a constructor function and have it accept the component’s props as an argument.

[Line 5] We call SearchBar’s parent constructor through the super call. There are two important things to note here. First, whenever we explicitly declare a child constructor, we have to call super. If we don’t, the this keyword will be undefined. Second, we pass props as an argument to the super call. Doing this gives us access to props throughout our SearchBar component through this.props.

Check it out yourself. If you delete the super call, you’ll see a terminal error stating ‘this’ is not allowed before super(). If you include the super call without passing it props, then try to log this.props, this.props be undefined.

[Lines 6-8] We set our initial state, which consists of a key called searchTerm assigned an empty string to start.

[Line 9] We explicitly bind this to the handleInputChange event handler. This will require further explanation which I’ll get to next.

[Lines 13-15] Each time the input box value changes, handleInputChange will be called, which is where we set the new state. To set the state, we call the setState function defined in SearchBar‘s parent, React.Component, and assign the latest value to searchTerm.

A bit more about the explicit this binding on [Line 9]. You may know that the value of this inside a function depends on how that function was called; it depends on what was on the left-side of the function at the call site. Because we are passing handleInputChange down to the input component, we want to ensure that when input invokes handleInputChange, the this value points to SearchBar. In other words, we want handleInputChange to be invoked as if SearchBar was on the left-side of it. That way, the this value will contain all the properties we expect such as props and the setState function.

Explicitly binding this is required for ES6-style components (but not for components created ES5-style). Without the explicit binding, setState inside handleInputChange will fail to resolve, leading to this error:

We’ll be doing more explicit binding of this as we build out our other components. For coverage about all the intricacies of this, I recommend Kyle Simpson’s excellent You Don’t Know JS series.

So that’s all it takes to update a component’s internal state. From here on out, each time the value in the input box changes, handleInputChange will be called, which in turn will update our searchTerm state to the latest input box value.

Before we move on, note that we should always update state using the setState function, and never change it directly (e.g. this.state.searchTerm = “don’t do this”). Mutating state directly bypasses React’s state management system and can result in unpredictable behavior.

Finally, the ESLint error previously showing for SearchBar (Component should be written as a pure function) should now be gone. You’ll understand why when we look at the two ways to create ES6-style components.

Alright, so now we have a SearchBar component which tracks a piece of its internal state. We can now use it to fire a search request at Spotify. Let’s take a look at the API methods we’ll be using.

Using the Spotify API
We want to use the Spotify API to:

  1. retrieve an artist’s albums,
  2. retrieve an album’s tracks,
  3. play a preview clip of a track.

Fortunately, at the time of this writing, Spotify does not require us to register for an API key. Let’s take a look at what Spotify provides by sending it a few search queries.

I’ll be using the excellent Postman for Chrome to try out the API. I highly recommend Postman, but using an online service like hurl.it, your browser directly, or even curl will work.

To retrieve an artist’s albums, I set up Postman like so and click Send:
postman_search_album

If you’re not using Postman, just copy and paste this into your browser bar:
https://api.spotify.com/v1/search?q=My%20Bloody%20Valentine&type=album

What we get back is a JSON payload listing the artist’s albums, with each album accompanied by the album name, ID, and album cover at multiple dimensions, among other information.

In a browser, the JSON response payload looks like this:
json_albums_payload

We can see that the albums are in the items array.

If you take one of the URLs from an album’s images array such as this:
https://i.scdn.co/image/9b81a34f8aed2f82bb9287764eb520d2af1e6172

and paste it into the browser bar, you should get the cover.

Now let’s try retrieving the tracks for an album. Take one of the album IDs in the payload. I’ll be using the ID of the first album in the items array:  3GH4IiI6jQAIvnHVdb5FB6.

To retrieve an album’s tracks, use this request:
https://api.spotify.com/v1/albums/3GH4IiI6jQAIvnHVdb5FB6

What we get back is a JSON payload with information about the album. The payload also includes an object called tracks , which has an items array holding the tracks:
json_tracks_payload
One key of interest accompanying each track is the preview_url. If we copy and paste one of these such as:
https://p.scdn.co/mp3-preview/3e01581bd39f90b2248770cbf52dae0553ccf2ab

into our browser bar, the browser should (hopefully) play a 30-second clip of the track.

Ok, so we now know how to get albums, get tracks, and play a preview of each track. Summarizing the API calls needed:

  • Retrieve an artist’s albums: https://api.spotify.com/v1/search?q={artist}&type=album
  • Retrieve an album’s tracks: https://api.spotify.com/v1/albums/{albumId}
  • Play a preview: Hit the preview_url of the track we’re interested in.

Great, let’s start moving this functionality into our app.

Fetching data
To fetch data from Spotify, we’re going to use a library called axios, a promise-based HTTP client. Start by installing it like so:

Next, in your src directory, create a directory called api.

Inside the api directory, create a file called musicApi.js. We’re going to put our calls to Spotify in musicApi.js, isolating them in one place. Your project’s src directory structure should now look like this:

Populate musicApi.js:

Our API is straight-forward, but let’s do a quick walkthrough. At the top, we import the axios library.

[Lines 3-8] We declare a generic fetch function which takes a request to send, and a callback to pass the response to. We pass the request to axios’ get method, which returns a promise. Once that promise resolves (i.e. data is available), we call our callback with it. Axios stores the actual payload content in the response’s data object.

[Lines 10-13] In this function, we use a template literal to form our album request before calling fetch with it.

[Lines 15-18] Here we do the same for tracks.

Let’s take stock of where we are. We have an App container, a SearchBar component, and an API which can help us retrieve music from Spotify.

Let’s move on to creating our AlbumList component.

Album List
In your component directory, create AlbumList.jsx:

[Line 3] We define a function called AlbumList which takes a props argument.

[Line 4] props will have an albums property which holds the array of albums we want to render. We map over the albums, creating an array of <li> elements, with each holding an album name.

[Lines 6-10] We return a <ul> element, with our list of album names inside.

[Lines 13-15] This is our first encounter with propTypes. In development mode, React checks the props that are passed into a component. For each props property, React attempts to look it up in the component’s propTypes object to ensure that (a) the prop is expected and (b) the prop is of the correct type. In this case, we’re specifying that the AlbumList component is expecting a props property called albums, that it’s an array, and that it’s required.

Your app will still work without this propTypes object, but you’ll see errors in your browser console as well as from ESLint.

Now clearly the AlbumList component has been created differently:

  • It does not extend React.Component.
  • It’s a function, not a class.
  • It does not have a render method.
  • It’s passed props explicitly.

There are reasons for this. Let’s briefly go over the difference between a component such as SearchBar, and a component such as AlbumList.

Two Styles of Component Creation
There are two main ways to create a component in React:

  1. As a stateful component.
  2. As a stateless, functional component.

A stateful component is exactly what it sounds like: it tracks some form of internal state. In addition, by extending React.Component, it also must have a render method, and may optionally implement other methods such as Lifecycle callbacks.

Lifecycle callbacks are handy when you want to be notified when a component is about to be rendered, or updated, or at another step in its lifecycle. A stateful component also has access to the this keyword through which it accesses its props (this is assuming you handled this correctly in the constructor as mentioned earlier).

SearchBar.jsx is an example of a stateful component. Taking a look at it as it currently is:

We can see that it tracks the value of the input box as a piece of internal state, implements a render method, and also uses the this keyword to pass the handleInputChange method down to the input component.

In contrast, a functional, stateless component is a pure function which doesn’t track anything internally. When given X, it always outputs Y.

AlbumList is an example of a functional, stateless component. It doesn’t need to track state, it doesn’t need access to the this keyword, and its sole responsibility is to render an array of albums passed in through its props.

How do you choose between creating a stateful and a stateless component?

My view is that state in general is like a useful virus that needs to be contained. A little bit helps us build what we need to build. But a lot of it, spread out, leads to buggy code that’s hard to reason about. So in general, favor creating functional, stateless components as:

  • being functional and stateless, they are easier to reason about, test, and debug.
  • props are explicit and there is no need to wrestle with the intricacies of the this keyword.
  • they are leaner than their stateful counterparts.

This is why ESLint is still complaining about how our App component should be written as a pure function, since it currently doesn’t track any state and can be technically written in the preferred stateless form. We’ll keep it as a stateful component as we’re going to track state in it soon.

There are a few advanced exceptions where you may still want to make something a class-based (stateful) component even without tracking any internal state. For example, one lifecycle method available is shouldComponentUpdate, which allows you to write custom code to check whether a component should update at all. If you can write a fast check here, you may get improved performance, but to start with that is often premature optimization.

Let’s wire this stuff up and get something showing on the screen.

Retrieving Albums
It’s finally time to retrieve albums and display them on screen. AlbumList is ready to receive an array to render, so no changes needed there for now.

What we need to do is use SearchBar‘s input box value as a search term for our musicApi. Let’s start by modifying index.js by adding the highlighted lines:

[Lines 4-5] We import our AlbumList component and all the functions  from musicApi.js.

[Lines 8-9] We create a constructor and call super. Notice that we don’t pass in the props argument because, being the overall container, App doesn’t require access to it. However, we still call super in order to gain access to this. Without calling superthis remains undefined.

[Lines 10-12] We initialize a piece of state called albums, assigning it an empty array as its value. This state will hold the list of albums retrieved for the current artist.

[Line 13-14] We explicitly bind this to the getAlbums callback we intend to pass to the SearchBar component, and the processAlbums callback we intend to pass to musicApi.

[Lines 17-19] This is the function we’ll pass down to our SearchBar component as one of its props. When a user hits enter in the input box, App‘s getAlbums function will be invoked. getAlbums in turn will call musicApi‘s getAlbums function.

[Lines 21-25] This is the function we pass our musicApi to call back on once it retrieves the albums.

[Line 30] We pass App‘s getAlbums function down as a prop to SearchBar.

[Line 31] We pass our array of albums down as a prop to AlbumList. Since the initial value of the albums state is an empty array, nothing will be rendered.

Because our App component now tracks some state, the ESLint error should now be gone.

Let’s make the necessary changes to SearchBar.jsx. Add or modify the highlighted lines:

[Lines 10] Explicitly bind this to the handleKeyPress event handler.

[Lines 19-23] handleKeyPress will detect when the ‘Enter’ key is pressed. Upon that happening, the passed-in getAlbums function will be called with the searchTerm.

[Line 26] We pass our handleKeyPress event handler to the input component.

[Lines 30-32] We specify that our component expects a prop called getAlbums, the value of which is a function, and that it’s required.

Let’s give the search feature a try.

If you don’t already have it running, fire up your dev server. Enter an artist into the search box and hit the Enter key. Your browser should now render a list of albums in response:
first_searchTo summarize the logic flow, here’s what’s happening:

  1. User types a search term into the input box.
  2. User hits the Enter key.
  3. SearchBar, through its props, calls getAlbums in index.js, which leads to getAlbums in musicApi.js getting called.
  4. musicApi makes the call to Spotify. When it receives a response, it passes the response to the callback. In this case, the callback is processAlbums in index.js.
  5. processAlbums updates the piece of internal state called albums, assigning it the array of items in the payload.
  6. This new state is passed to AlbumList, which then re-renders the list of album names.

Despite everything working, if you look at your browser’s console output, you should see something like this:

When we render lists of children as we do in AlbumList, we should supply each list item a unique key. React then uses these keys for reconciliation during state changes, reordering, or filtering. This subsequently leads to better performance. In the absence of explicit keys, React uses the array index as the key (but it’ll still complain anyway). We’ll remedy this when we create the Album component.

Before we build more components, let’s go over how React re-renders the album list as you make new searches.

The Virtual DOM
What makes a Single-Page Application (SPA) like ours appealing is the fluidity of interaction. Whenever you invoke a new search, the album list updates without requiring a full page reload. Likewise, when you use an app like Gmail and pull up an email, the inbox gets ‘hidden’ and replaced by the message, while the sidebar and other parts of the page remain. This leads to a snappy, desktop-like experience.

Delivering this experience requires figuring out which part of the DOM to update when a change or interaction occurs. Different Javascript frameworks use different strategies. Ember uses data-binding, Angular 1 uses dirty checking, and React uses the Virtual DOM, which we’ll briefly cover.

When a component’s render method is first called, it outputs a model of your DOM called a Virtual DOM, not the actual DOM elements themselves. The Virtual DOM is a Javascript data structure representing what your DOM should look like. React then takes this representation and generates the actual DOM elements from it.

From then on, any time there’s a state change in your component (i.e. setState is called), the component’s render method will be invoked, and a new Virtual DOM created. This new Virtual DOM is then diff’d against the previous Virtual DOM. The results of this diff operation represent the actual DOM changes to make. Your DOM is then ‘patched’ with these changes, resulting in a change in the display.

Let’s walk through how this applies to our app in its current state:

  1. At startup, our album list is an empty array. When our App‘s render method is called, the Virtual DOM has no data representing our list of albums, resulting in nothing being displayed.
  2. After a search is executed and results returned from our musicApi, setState in index.js is called, where the albumList state is set to the array of albums returned.
  3. React detects this state change and calls render, which outputs a new Virtual DOM representation.
  4. This new Virtual DOM is diff’d against the previous Virtual DOM, and it’s determined that the album list has changed (from an empty array to something).
  5. A DOM patch is generated and takes effect, resulting in our list of albums getting rendered.

Subsequent artist searches follow the same flow.

The implications of this are that:

  1. Only the parts of the DOM which need to change are changed.
  2. The DOM changes are batched for greater efficiency.
  3. For you as the app developer, DOM updates are automatic and taken care of.

Now that we have a handle on how React re-renders when there’s a state update, let’s look to improve the look of our app.

A Detour Through Aesthetics
In this section, we’ll spruce up our app with better layout and styling. Nothing fancy. Just enough to get it to demo quality.

First, let’s get rid of displaying albums with text and use album covers instead. Make the following change to AlbumList.jsx:

After the change, our app should look like this:
album_covers

For layout, we’ll be using Bootstrap. We won’t be using much of Bootstrap, so to keep it simple, we’re going to just import Bootstrap directly from a CDN in our index.html:

Next, we’ll apply some basic styles to our SearchBar and AlbumList components. With React, you have the option of using plain CSS styling, or inline styling. The former is the same thing we’ve been doing for ages. You simply create a style.css file, import it in your index.html file, and then refer to the selectors.

Inline styling is styling using Javascript. With inline styling, you create a Javascript object representing your styles, then pass that object as a prop to your component.

I actually prefer using an explicit css file. The technique is well-understood, more reusable, and industry standard. However, because this is a tutorial, I’m going to use inline styling to just show you a different way to approach styling React components. This way, you’ll know both approaches and can choose for yourself.

Let’s start with the SearchBar component. Make the highlighted additions and changes to SearchBar.jsx:

Examing this from the bottom-up:

[Lines 43-51] We add a styles object to our SearchBar component. The styles object itself has styling for a div, and the input box. Naming the styling objects div and input is entirely my choice. However, notice how the Javascript keys in the div and input objects look like their CSS counterparts, except they’re in camelCase (e.g. textAlign vs text-align).

[Line 29-33] We pass the input component its style prop, specifying that its width should be 60% of its container’s width.

[Line 28] Just a label for the input box.

[Line 27] We now enclose the input component in a div, passing the div a style prop the value of which is the div styling object. In other words, we are specifying that this div should have a margin of 30px and its contents should be centered.

In addition, remove the <h1> from index.html [Line 8].

If you look at your app now, you should see the styling take effect:
centered_searchbar

To summarize, if you want to style React components inline, create an object representing the style you want to apply, then pass that object as a style prop to the target component.

Let’s also apply some styling to AlbumList.jsx:

Again working our way from the bottom-up:

[Lines 28-39] We create a styles object holding the styles we want to apply to the div and the ul elements.

[Line 17] The ul styling is passed as a style prop down to the ul component.

[Lines 16, 20] The ul component is wrapped in a div, which is also supplied a style prop. In addition, we use a bit of Bootstrap to place our album div in four columns.

The end effect is to render our list of albums with its own scrollbar:searchbar_scroll

 

This way, as we scroll, the list of tracks on the right will remain in view.

Now that we have our app looking good enough for a demo, let’s move on to creating the individual Album component.

Album
Currently we render our albums directly inside the AlbumList component. What we want is to have an actual Album component take care of it.

Start by creating Album.jsx in your components folder:

Hopefully by now the patterns are starting to set in and things are looking familiar.

[Line 3] We create the Album component as a stateless, functional component receiving explicit props. The props will contain one album to render.

[Lines 4-12] We return a list item representing the album. The item itself, an img element, includes some styling.

[Lines 15-17] We set up the propTypes specifying a props value called album is expected, and that it’s an object.

[Lines 19-23] We specify some styling for our img element.

We can now refactor AlbumList.jsx as follows:

[Line 2] We import our Album component.

[Lines 4-5] For each album, we instantiate an Album component and pass it the album object as a prop. We also now pass each Album component a unique key in the form of the album id. With this addition, the warning you see in your browser console should now be gone.

Our app should look identical to the way it was before the refactoring save for some spacing between the albums.

Let’s move on to retrieving, rendering, and playing tracks.

Track List
From here on out, we’re going to move pretty quick. Everything we’ve learned building the AlbumList and Album components applies directly to the TrackList and Track components we’re going to build.

Let’s start by creating TrackList.jsx in the components folder:

[Line 2] We import our Track component which, of course, doesn’t exist yet.

[Line 4] The TrackList component is created as a stateless, functional component.

[Line 5] For each track, we instantiate a Track component.

[Line 8-12] We set our div to span three columns, within which we have a ul component, passing it a style directly rather than declaring a style object. The ul component wraps our array of Track components.

[Lines 16-18] We tell React this component expects an array in its props called tracks.

Next, the Track component.

Track
In the components folder, create Track.jsx:

Similar to the AlbumList, Album, and TrackList components, the Track component is also a stateless, functional component with inline styling and propTypes.

I just want to point out [Lines 10-11]. The li component can take event handlers for mouse over and mouse out events. Here, we’re specifying that we want the list item to be a shade of blue when the mouse is over it, and white when the mouse is not.

Alright, so now that we have a TrackList and Track component, we need to retrieve the tracks themselves.

Retrieving Tracks
We currently retrieve albums by passing a getAlbums callback to our SearchBar component. When the user hits enter, SearchBar invokes getAlbums, which in turn leads to albums being retrieved from Spotify.

In a similar vein, we’re going to pass a getTracks callback to our Album component. When the user clicks on an album, getTracks will be invoked, which will lead to tracks being retrieved from Spotify. Because the Album component is a child of the AlbumList component, we’ll need to first pass getTracks to AlbumList. AlbumList will then pass the callback further down to Album.

Modify index.js as follows:

[Line 5] We import our TrackList component.

[Line 13] We introduce a new piece of state called tracks. Similar to the albums state, tracks will hold the array of tracks for the currently selected album.

[Lines 17-18] These are the callbacks we’re going to use. Since we’re going to pass them elsewhere, we explicitly bind this.

[Lines 25-27] This is the callback we’re going to pass to the AlbumList component. When it’s invoked, it’ll call musicApi‘s getTracks.

[Line 32] We set our tracks state to a blank array when a user retrieves albums for another artist. This way we won’t have albums for one artist listed on the left, with tracks from another artist on the right.

[Lines 36-40] This is the callback we’re going to pass to musicApi when we retrieve tracks. When tracks are received from Spotify, this callback will be invoked and our tracks state updated.

[Line 46] We modify the AlbumList instantiation to include a getTracks prop, the value of which is our getTracks callback.

[Line 47] We instantiate a TrackList component, passing it an array of tracks as a prop.

Next, we need to have AlbumList pass the getTracks callback down to Album. This is done with a simple modification in AlbumList.jsx:

[Lines 5-6] All that’s happening here is that we’re taking the getTracks prop passed down from App, and passing it further down to Album.

[Line 19] We declare that the AlbumList component expects a getTracks function prop. Even though we’re just passing it down, we still need to declare it since we reference it.

Lastly, we’ll modify Album.jsx to invoke the getTracks callback in response to a click:

[Line 10] We assign an inline function to the img component’s onClick prop. Now when a user clicks an album image, getTracks will be called.

[Line 18] Standard propType declaration.

Alright, let’s give it a try. If you click on an album cover now, you should see a list of tracks render on the right (make sure your browser window is wide enough for the albums and tracks to be side-by-side):
track_list

Now that we can retrieve tracks, the final step in this post is to play a preview of a track when the user clicks on it.

Track Preview
The same callback pattern we’ve been using so far applies to playing track previews.

We’re going to pass a playPreview callback down to the TrackList component. TrackList in turn will pass the playPreview callback down to the Track component. In the Track component, we’ll capture user click events and invoke the playPreview callback accordingly.

Let’s start by modifying index.js:

[Line 15] The currentPreview variable will represent the current preview we’re playing in the form of an Audio object (This was previously a piece of the state object, but as Adrian pointed out in the comments, this is unnecessary since no React component cares about it and nothing on the page actually needs to update when we play different previews).

[Line 20] We explicitly bind the playPreview callback we intend to pass to TrackList.

[Line 44-54] In the playPreview callback, we first check whether we have a preview currently playing. If so, we pause it. We then create a new Audio object for the preview we currently want and assign it as the new currentPreview before playing it.

[Line 61] We pass the playPreview callback down to TrackList.

You’ve probably guessed what we need to do in TrackList.jsx:

[Lines 5-6] We pass the playPreview callback down to Track.

[Line 19] We set our propTypes expectations accordingly.

Finally, in Track.jsx:

[Line 12] We pass an inline function to the li element’s onClick prop. When a list item gets clicked, the playPreview callback will be invoked.

[Line 21] Declare getTracks in the propTypes.

Alright, time to take our app for a spin. Search for an artist’s albums, retrieve the tracks by clicking an album cover, and then click on a track in the list. You should hear a 30-second preview come through.

Onward
In this post, we learned the finer points of creating React components and composing them to create a front-end app. If you followed along, then congratulations on getting a React app up and running.

In the next installment, we’ll explore how to improve our state management with the Redux library. In the meantime, if you have any comments, suggestions, or corrections, please feel free to post them in the comments section or shoot me an email.

2016.08.04 Update
A couple of readers (Kyriakos and Ben) commented about how quickly the App component increases in complexity as we add more features, and asked what to do about it. Those were sharp observations and indeed, things would get out of hand quickly if we continued this course.

For this tutorial, almost all the logic and data were kept in the App container to demonstrate downward data flow from parents to children, and to focus on keeping components stateless wherever we could. However, as an app grows in complexity, we need better ways to add functionality without losing our sanity.

And that’s what we’ll be doing in the next installment. In the same way we decomposed our UI into individual pieces, we’ll be decomposing our state management into a clear update pipeline. Thanks for the feedback!

 

46 Comments A Primer on the React Ecosystem: Part 2 of 3

  1. Bluebar

    Thanks for this tutorial. I just started ReactJS yesterday and I find this immensely helpful. I am now excited about Redux. Keep up the good work!

  2. Larry Kubin

    On the second to last code snippet (TrackList.jsx), I ended up needing to pass in the track.id as a key. The key was present in an earlier snippet, but seems to have gotten removed.

    const tracks = props.tracks.map((track) =>
    );

  3. DabeDotCom

    This is an excellent tutorial! It does a great job introducing the basic concepts early, with just enough “cleverness” to demonstrate the more interesting features as you go.

    (I found myself making the code changes myself, *before* reading the subsequent paragraphs — and MOST of the time, I was right! That shows the tutorial really did its job of helping me LEARN, not just follow along blindly…)

    I eagerly anticipate Part Three. :-D

    1. Nitin Punjabi

      Thanks for the message. It’s great to hear you were moving ahead of the tutorial. Also cool to see Larry above catch the code error.

  4. Kyriakos

    Great tutorial. Thanks.

    What troubles me is that as new components are created the wrapper component (app) keeps growing with functionality that does not necessarily feel like it should be part of it. Is this the proper way or its just for the sake of the tutorial?

  5. Ben

    Great tutorial! One thing I’m wondering though is that through this pattern – using App to pass wrappers to API calls directly to the components – App will get longer and longer as the application grows in complexity. It is currently around 72 lines long. How would this be addressed so that App doesn’t become a huge repository of intermediary code?

    1. Nitin Punjabi

      Hey Ben:

      I agree. As the app grows, we need better ways of doing things. And I hope Part 3, which is dedicated to addressing the issue of state management, illuminates one approach to the problem.

  6. Ramiro

    Excellent tutorial!! Just getting started with React.
    You have a very clear and consistent way of explaining everything.
    Can’t wait to read the third chapter in this React adventure.

    Thanks a lot!

  7. AndriesVh

    Super tutorial! Can’t wait for the 3th part. I also hope that Typescript will be added to the build flow in the next part.

    1. Nitin Punjabi

      Hi Andries:

      I’ve been meaning to pick up Typescript for a while but I haven’t had the chance, so it won’t be unfortunately.

      I found these two links (as I’m sure you have):
      https://www.typescriptlang.org/docs/handbook/react-&-webpack.html

      http://www.jbrantly.com/typescript-and-webpack/

      From my cursory read, incorporating TS into the Webpack build follows the same steps:
      1) Install the loader
      2) Specify you want to use the loader in the module object of webpack.config.js

  8. jason kerr

    bonus points for explicitly explaining how to bring linting into this process. i had to fight with it a little as the plugin versioning is a bit dicey as you mentioned but a cursory look at http://survivejs.com/webpack/advanced-techniques/linting/ should set experienced tutorial junkies straight.

    much better than the facebook react tutorial. that one skips a lot of steps and leaves a lot to be assumed. if anyone can get through those, this will be a piece of cake.

    i’m still amazed what a little ajax and an API that serves JSON objects can accomplish.

  9. James Riall

    Incredible tutotial, learned a lot from going through this and I’m sure I’ll pick up even more tomorrow when I plan to go through it again and then use what I’ve learned to build a similar project using the GitHub user API.

  10. Yoann

    Thank you this is a very good reading! Didactical with a great example. I am yearning for part 3!

    I wonder how testing (unit tests, UI components tests) would fit into this framework.

    1. Nitin Punjabi

      Thanks for reading, Yoann. I’ve been buried in work/life issues but I’m looking to get Part 3 published next week. Perhaps I can write about testing in a follow-up article.

  11. adrian

    Nice writing. My two cents, the current track doesn’t need to be part of the state, since it isn’t involved in the dom. Updating the state will trigger a re-render which will do nothing. You can store currentPreview as a simple property of the app object.

    1. Nitin Punjabi

      Yes! I wanted to get Part 3 out sooner but all sorts of things have come at me all at once.

      I will have Part 3 published before the middle of next week.

    1. Nitin Punjabi

      I see buttons when I run it on Firefox (Ubuntu), Chrome (Ubuntu), and Edge (Windows 10). Can you send me a screenshot?

  12. BDupree

    I will send it now.

    I am using EDGE (WIN10). I am also just using a copy of your code from Git.

    I actually have these two problem:

    1. Scroll bars show around Album list but the list is not scrolling and no scroll bar buttons show
    2. Mouse click does not set focus on . I can only get to the search field by using TAB

    I am evaluating React to replace a current JQuery App.

  13. BDupree

    From a debugging point of view, I have installed the Chrome Dev Tool Extension for React and it is nice – it allows inspection of the props and state of the React components as the application is navigated.

    But because babel is transpiling and webpack is bundling, is the main way to debug code just using old fashion console.log?

    1. Nitin Punjabi

      console.log is one way.

      Another way is to put ‘debugger’ statements in your code:
      https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/debugger

      When your browser detects a debugger statement, it’ll consider it a breakpoint and launch your browser’s devtools. You’ll then be able to step through the code from that point onwards.

      And another way is tool-specific. For example, in Part 3, I’ll be covering state management with Redux, which comes with a couple of handy tools to monitor:
      1) What your state was
      2) What caused your state to change
      3) What’s your state now

      Check out the illustrations on this page:
      https://github.com/gaearon/redux-devtools

  14. Mark

    This is fantastic. A really clear, concise introduction to React.
    Thank you, Nitin.

    (Any idea when you’ll publish part 3? – looking forward to it!)

  15. Andy Neale

    Even better than Part 1!

    It’s reassuring to know that I’ve ended up developing my application using a very similar approach and structure, which is great because it means I’m doing it right (but frustrating because it means I could have just read this guide and saved myself days and days of reading other inferior how-to guides and hacking around to get it working!)

    And it’s given me some useful pointers on how to improve my existing code (e.g. using stateless functional components where state isn’t required).

    Can’t wait for Part 3!

Comments are closed.