Cabin – React & Redux Example App – React

11 min read
Nick P.
Nick P.
Published June 6, 2016 Updated March 25, 2021

This is the 2nd post for Cabin, the React & Redux Example App Tutorial series created by Stream. The final result of following this series is your own feature-rich, scalable social network app built with React and Redux!

Visit getstream.io/cabin for an overview of all the tutorials, as well as a live demo. The source code can be found on the Stream GitHub repository for Cabin, and all blog posts can be found at their respective links below:

  1. Introduction
  2. React
  3. Redux
  4. Stream
  5. Imgix
  6. Keen
  7. Algolia
  8. Mapbox
  9. Best Practices and Gotchas

Introduction

Welcome back to the Cabin tutorial series! With this post, we will be going over the basics of React. React is, of course, a critical component of Cabin - which is a React/Redux example app after all!

Overview

Here is what you will be learning in this post of the series:

  • Defining React
  • The History of React
  • Why React?
  • How React Works (Under The Hood)
  • The JSX Markup Syntax
  • React Components
  • Props, Event, State

Okay, ready to Rock N' Roll? Rock N' Roll... N' React? Let's jump in!

Definition

So, what is React? A client-side JavaScript library? Well, yes. But React is not a client-side JS library quite in the sense of a monolithic client-side solution such as AngularJS, or a varied toolkit such as jQuery. Let's look at a definition of React: React is a library for providing a view of data rendered as HTML. Some people like to think of React is the V (View) in Model-View-Controller (MVC) architecture. That probably sounds vague (and maybe sort of boring, honestly) - but no worries, let's continue on for now as we will be going over a lot to further our understanding of React. By the end, you will be excited and informed!

History

React was open sourced by Facebook way back in May 2013 at JSConf US during Tom Occhino and Jordan Walke's presentation "JS Apps at Facebook". There is even a video of this presentation, which you should watch for educational purposes. Just by watching this presentation, you will have a solid grasp on what React is, and why it was originally developed by Facebook. Watch the original presentation on React:

Present

Today, three years later, the React library is used in production not only by Facebook and Instagram but also by web titans such as Netflix, Twitter, Imgur, Airbnb, SeatGeek, and many more. React is also the 7th most starred repo on GitHub.

Why React?

Okay, so, we have a simple (if not somewhat vague) definition of React. And we know that it is rapidly grown to be a popular, well-supported way of rendering views in JavaScript. But a good question still remains: Why would someone want to use React? Think about these three reasons to use React:

1. Simple

With React, you express how your app should look at any given point in time - and it will automatically manage your UI updates when your underlying data changes.

2. Declarative

When the data changes, React conceptually hits the "refresh" button and knows to only update the changed parts. This provides performance.

3. Reusable

React is all about building reusable components. In fact, with React the only thing you do is build components. Since they're so encapsulated, components make code reuse, testing, and separation of concerns easy. Simple, declarative, and reusable. These are great qualities of any type of framework - and in our tutorial, we will break down how this is achieved.

Other Benefits of React

So, someone (your boss, partner, friend, enemy) asks you some other real-world benefits? What do you tell them? Go over other benefits of React:

  • Performance - extremely fast, low memory footprint
  • Sets up a structure that makes it easy to build small, reusable UI components
  • Plays well with third-party libraries that can be mixed and matched
  • Easier to integrate into existing code base
  • Proven, large, and growing ecosystem that makes it easy to find more developers

How React Works

To better your understanding about React, let's discuss how it works under the hood. One of the largest benefits of React is performance. React is fast, and has a low memory footprint which is achieved by abstracting the DOM (Document Object Model) with a virtual DOM. In terms of data binding, most front-end frameworks use either Key-Value Observation (Meteor, Ember) or Dirty Checking (AngularJS). React is different and takes a more JavaScript approach. Let's look at how React works:

  • Abstracts the DOM with a virtual representation of the DOM that is kept in memory
  • When the data model changes, React re-renders only the components that use the data that has changed
  • "Diffs" the previous virtual DOM with the new virtual DOM representation
  • Batches updates to the actual DOM, and only modifies what has changed

So, React is essentially a DOM diff-ing engine, using the virtual DOM concept. 2x Extra Credit: Build your own Virtual DOM!

JSX

Before we get into Components, the building blocks of React, we should first have a discussion on JSX - a XML-like syntax unique to React that we will use to construct these building blocks. JSX is one piece of React that hangs up a lot of developers initially.

Definition

Study these two definitions of JSX:

JSX is a XML-like syntax extension to ECMAScript without any defined semantics.

Or, in slightly other words:

JSX is an inline markup that looks like HTML and gets transformed to JavaScript.

Check out a couple other things here to think about with JSX:

  • JSX is an "extension" to ECMAScript in the way that it is not actually part of ECMAScript. Therefore, it requires preprocessing. A common way to do this is Babel. Considering we are also writing ES2015/ES6/ES7 code for Cabin - we are using Babel because it handles that preprocessing as well. Learn more about Babel.
  • You don't have to use JSX, but it is a much more elegant way of writing React. An example of the alternative to using JSX can be found here. This post is useful to see React stripped down to its core (no JSX, no Webpack, no Flux/Redux), but it is not a recommended way of creating a production application.

Rethinking Best Practice

One reason that developers do not like the idea of JSX is the mixture of markup (HTML/XML) and logic (JavaScript). It has been considered best practice for a long time to separate these concerns. In case of React, however, it ends up being the more elegant way of doing things. For Cabin, we organize our React application structure to have a separate file for each of our components. This makes our JSX separate and modular by concerns, not file types. It turns out this works well, and maybe the whole "separating HTML from JavaScript" thing does not make as much sense as previously thought.

JSX Code Example

In your Cabin project, open app/modules/components/Comment/index.js:

js
import React, { Component } from "react";
import { Link } from "react-router";
import TimeAgo from "../TimeAgo";
class Comment extends Component {
  render() {
    return (
      <div className="comment">
        <Link to={`/profile/${this.props.userId}`}>
          <div className="actor">
            {this.props.firstName} {this.props.lastName.charAt(0) + "."}
          </div>
        </Link>
        <div className="time">
          <TimeAgo timestamp={this.props.createdAt} />
        </div>

Have a look at the JSX - which is what is returning inside of the render() method. JSX does look like XML - we have attributes, and children. If an attribute value is enclosed in quotes, the value is a string. When the value is in braces - the value enclosed is a JavaScript expression. In the example above, we are passing props in our expression braces. We will go over props more in the section on React components.

className

One "gotcha" of JSX here is className. If you did not already know, there is a set of reserved words in JavaScript. One of them happens to be class. Having class reserved makes total sense now, because we now have classes in ES2015. So to get around this conflict in JSX, we use className in place of class. Overall though, JSX looks and feels pretty much like XML/HTML.

Tag Names

Tag names are created in JSX based on the name of the component. So, our component Comment can now be used like:

js
<Comment />;

And what can be used - can be reused. Now you see how JSX is used to construct a reusable component. Next we jump into React components in far more detail. Keep reading!

Components

As you know by now, the heart and soul of React is the component. In the previous section on JSX, we showed how the XML-like markup syntax is used to construct a component. In this section, we will first dive into a very simple, non-Cabin example to understand. Then, we will apply these principles to Cabin, which is built with a complex application structure.

Basic Example

Look at this basic, non-Cabin code example:

js
// Create a component named MsgComponent
let MsgComponent = React.createClass({
  render: function () {
    return <div>{this.props.msg}</div>;
  },
});
// Render an instance into document.body
ReactDOM.render(<MsgComponent msg="Hello there!" />, document.body);

Here we get to see what parts of React are called upon to work their magic. Think about the two major things happening in the above example:

1. The Component is Created

createClass() is called to create a single MsgComponent child from an object that has a single property, render(). render() is an anonymous function that returns the JSX markup. Note: render() is the only required piece of the object used by createClass() - but we can actually pass many other properties. However, render() is a vital piece of the React system - as it describes our component to the virtual DOM.

2. The Component Rendered to DOM

MsgComponent is rendered with the render() method of ReactDOM. ReactDOM allows us to get outside of the React model to get to our document (DOM) for making real use of React in our webpage. In this example, the component is rendered in the body of document. We have added a msg property to our MsgComponent before rendering. Inside of our JSX markup, we can use these properties by accessing them like we do in the example, using a single curly brace, referencing this.props.

Example from Cabin

Open app/modules/components/Comment/index.js - which is where the Comment component we saw in the JSX example lives:

js
import React, { Component } from "react";
import { Link } from "react-router";
import TimeAgo from "../TimeAgo";
class Comment extends Component {
  render() {
    return (
      <div className="comment">
        <Link to={`/profile/${this.props.userId}`}>
          <div className="actor">
            {this.props.firstName} {this.props.lastName.charAt(0) + "."}
          </div>
        </Link>
        <div className="time">
          <TimeAgo timestamp={this.props.createdAt} />
        </div>

Nested Components

React components can also be made up of other React components. In the example above, we are doing just that - importing TimeAgo at the top of the block, and then using the component in our JSX markup for Comment. And we can keep building on this concept. We can use yet another component, CommentInput, inside of our Comment component:

js
<Comment>
  <CommentInput />
</Comment>;

So, here's a screenshot of the UI, with the components visualized like so:

This is the first step from Facebook's excellent "Thinking in React", which is to "Break the UI into a Component Hierarchy". Take a look at "Thinking in React" - the Facebook team does a great job explaining how to understand React's core philosophies.

Props

In our examples, we have seen props (properties) passed to our components. We have also seen how they are accessed in our components via this.props. Props are part of the reason React is good at managing state as they provide a system for passing data from parent components to child components. Another way to think about it - props are to components as arguments are to functions. Props are for immutable data that isn't going to change, whereas state is for data that is intended to change. We will discuss state in the coming section. Our PhotoList component is a good example of passing data down from parent to children. Open app/components/PhotoList to see the following: PhotoItem.js Our PhotoItem sub-component uses yet another component called PhotoFooter, which we can pass props down to like so:

js
<PhotoFooter {...this.props} onLike={this.props.onLike} />;

Note on Cabin Application Structure

The way our example application is structured - our main components have index.js files in directories named for the component. Sub-components are used to compose our main components - and have their own files that are named for the component.

Events

In the PhotoList component, we are also introduced to concept of events in components. We have a renderItems() function that maps each photo in the this.props.photos array to a PhotoItem component. Open up index.js to see the following:

js
class PhotoList extends Component {
  renderItems = () => {
    return this.props.photos.map((photo) => (
      <PhotoItem
        key={`photo-${photo.id}`}
        {...photo}
        onLike={this.props.onLike}
      />
    ));
  };
  render() {
    return <ul className="photo-items">{this.renderItems()}</ul>;
  }
}

This is a more declarative way to compose a list of photos than say something like Angular's ng-repeat directive. Note that this is a cool thing about React - we can pass functions as props. This allows us to not only but to add event handlers to our components. We could, for example, pass a function as a handler for an onClick property. While inline event handlers may sound like bad practice to some, in JSX it works just fine.

State

So, the thing is called React, right? But so far we haven't seen too much reactivity. Well, that starts to change here. Above we explained how props are part of the reason React works well to manage state. But without a more dynamic component, React would just be a decent static rendering engine. This is where state comes in. Unlike props, state is controlled and managed internally by the component. Props are external and the control lies in the parent.

State Example from Cabin

A good place to see and understand how state works within the Cabin app is in our upload functionality. Open app/modules/routes/Upload/Upload.js. Note: As you can see, some of our components in our app actually live in the app/routes. This is because we are using React Router. React Router is it's own beast, and to do learning it proper justice you should check out the tutorial from the React team. You will not be disappointed! 2x Extra Credit: Go through the official React Router tutorial! Initial State

js
class Upload extends Component {
    state = {
        caption: '',
        hashtags: '',
        location: '',
        filename: 'Select Image',
        uploadState: 'Upload',
        disabledUploadState: false,
    };
...

The first thing we do at the top of our Upload class is add an object for initial state. Alternatively, we could add a getInitialState() method. Using State Using state is as simple as using props:

js
<span id="filename">{this.state.filename}</span>;

Setting State To update state, we need to call a function in our component - this.setState(). React will then re-render our component with the new state - which updates the UI. This is at the core of React - a more declarative way to manipulate our DOM. From our Upload component:

js
/**
 * handleCaptionChange
 * @param e event
 */
handleCaptionChange = (e) =>
  this.setState({
    caption: e.target.value,
  });
/**
 * handleLocationChange
 * @param e event
 */
handleLocationChange = (e) =>
  this.setState({
    location: e.target.value,
  });

There you have the basic toolkit of how to manage and display state. If you harken back to the How React Works section, you also know a bit of how state management is achieved "under the hood".

Redux

With React, we have a great way to handling our view. But how do we manage our state throughout our application? We can now certainly write code to handle state in our components, but how do we do this consistently? Let's move on to Redux - which we will pair with React in order to manage state not just in a component but throughout our application. Let's go to the next post of the series, Redux!