How to communicate between components in React

Comment

How to communicate between components in React

**All of the code in this post is going to be using JavaScript ES6 & class-based components for React.  

One of the topics I commonly find people struggling with in regards to React is how to keep track of and communicate data throughout their application. This is probably partially due to how different a React component (with their entwined state and logic) can feel from a traditional framework's view controllers. This is a really core concept to how React is intended to be structured and having a strong understanding of it enables you to build applications that work smoothly. I'm going to break this down into three general groups: 

  • Pre-render parent-child communication
  • Post-render parent-child communication
  • Sibling communication

This post is going to cover the first group, pre-render parent-child communication.


State & Props

The most common and widely used form of communication in React involves the state of your component and the properties (or props) that are passed down to child components. State is a component level concept, you can essentially think of it as the private data of your component. In the example below we'll define some initial state in our constructor function and make use of it in our render function through {this.state...}

**You can live-edit any of this code by the way.

It's important to note that you should never mutate state directly by assigning to this.state elsewhere in your app, rather, changes to the state of your application are triggered with React's setState() function. This is also the primary way that you will re-render the UI of your application as calls to setState trigger UI updates.

The basic use of setState is with simple key-value pairs, for example we could change the state of greeting in the previous example with a call to setState in some handler:  

this.setState({
  greeting: 'Welcome!'
})

This greeting would then be immediately updated in our UI anywhere that we have {this.state.greeting}. Knowing that state represents a consistent source of internal data for your component, and that this data is always reflected in your UI, quickly frees you to start building some pretty cool things. 

Here is something a little more advanced, we'll use a random hex code generator to set the state of this.state.color to a random color every 2.5 seconds and hook the state to an inline style to update the color of the block on each render:

While this is useful, odds are our React app is going to be built out of more than one component, and if it isn't we need to seriously reconsider what we're doing. So we need ways to communicate data across components, luckily React provides several.

I'm going to start out by discussing props. Props are the primary source of data communication in React and they operate in a unidirectional top-down manner. Parent components can pass props down to child components and child components down to their children, etc. Props, much like state, are plain JavaScript objects and should always be treated as immutable. They essentially serve to pass down configuration and functionality to React components further down the tree. They are commonly hooked to the state of a parent component (so that changes to the state of a component propagate down to its children), but don't necessarily have to be. They are pretty easy to understand once you see them in action, here is a basic example to help illustrate:

If you are looking to communicate some information back up to the parent, this is most often done with callbacks. We pass a function reference to our child components as props, which gives them the ability to notify their parent components that a state change or some other data handling needs to occur & the corresponding function should be executed. 

Here is a basic counter app as an example of this:

These examples are often what is referred to as Smart-Dumb component architecture. Your 'smart' components are responsible for the state of their component hierarchy, responding to events, processing data and passing along the necessary info to their children. While the 'dumb' components are strictly used to render the resulting data to the UI, the only logic they should really be implementing (if any at all) relates to the props that they receive from their parents. This is largely enabled by the fact that both props and state are deterministic, that is, for a given set of props and state the resulting output should always be the same.

This also leads to a pretty common shorthand way of representing 'dumb' components known as stateless functional components, where a React component whose only responsibility is rendering can be expressed as a basic function. 

This is the previous example with the child components refactored to be stateless functional components:

It's important to note that this isn't strictly necessary, but rather a recommendation from the React team as a means to help further improve the performance of React going forward. Although I personally find them helpful in quickly identifying a pure render component vs a class based component in my code, they have also become pretty common out in the wild so I wanted to give a brief overview here.


Context

And now we move on to some of the alternative ways of communicating in React. I'm going to start off by saying, before reaching for another tool in the shed consider whether your problem can be solved with props and state, even if you have to refactor things a little, because honestly 90% of use cases in React can be solved by correctly using props and state.

With that being said, context in React is similar in concept to global variables. If you have a situation in which you want to pass data down through some sub-tree of components without having to manually pass that data through props at every given step, context lets you do so. The most common use cases for this are things that would normally be represented globally like styles or a logged in user. Context involves a top-level context-provider that defines what is available to any child components if they ask for it. This is done by initializing some context values through the use of getChildContext(), along with defining some class properties on the context-provider and the context-user which are done with childContextTypes, and contextTypes respectively. 

It's a little clearer to see how this looks in practice:

It's important to note that getChildContext() can be updated by state changes, like just about everything in React, which again allows you to use it most effectively for things that are by nature global (or at least global to a given sub-tree), like application settings.

Here we'll take the previous example but add some state to the User component that determines the value of this.context.favColor:

Stateless functional components also have access to context in your application as the second argument to the function, provided that contextTypes is defined as a property of the function.

Here is one last simple example to illustrate: 

Again, just to emphasize, don't overuse context (or refs, which we'll cover next time). One of the most valuable things that you get from working with props and state for your parent-child communication is a very explicit data flow. You know, when looking at any given component, where its data came from and where its data is going, which is priceless as applications continue to grow. Don't be completely afraid to use the other methods available to you, just be sure to take stock and know when they best suit your needs.

That's it for part 1, In part 2 I'll cover post-render parent-child communication by referencing your rendered DOM elements with the React life-cycle method componentDidMount() using both vanilla JavaScript and a convenient React feature known as refs.

 

-Brad

Comment

Build your own responsive grid from scratch

Build your own responsive grid from scratch

A common feature of any modern website is responsiveness, having the page render appropriately to whatever device is displaying it rather than building a site specifically for that device. Almost all major CSS tools and frameworks include some form of a responsive grid that you can implement into your site. However, this can sometimes be massive overkill for the task at hand. Loading a full framework just to make use of a grid is like including jQuery into a project just to have slightly more convenient DOM selectors. Responsiveness is great, but adding a ton of code to handle something so simple is not. Luckily building your own responsive grid is really easy, only requiring a bit of basic math and CSS. 

I'm going to preempt this by saying if you are looking for a standard grid between 2-12 columns wide, and want to skip the framework, there are a number of generators out there that do what we're going to be doing below. Heck you could probably build your own if you are so inclined. I would most highly recommend the Responsive Grid System by Graham Miller, it produces straightforward quality code that you can plug directly into any website you may be building, and can save you a few minutes if you are in a bit of a rush. On top of that it showcases some really useful standards that you can use in your own grids, like resetting the margin of our first-child column and giving our clearfix a better name.

Alright, so let's take a look at how we go about calculating our grid. If you've done any work with responsiveness before you'll likely be familiar with the formula (Target / Context) * 100 = Result, which is essentially a simple measure of the relative size of a child element to it's parent. A fluid grid just takes this and extends it a touch to include multiple elements and the margin or spacing between them. 

Let's use an example of an 8 column grid with 2% margin spacing between the elements:

Style.css

/* Our basic CSS for any custom grid */
/* Gives us some useful standards to start off */

.column {
  display: block;
  float: left;
  margin-left: 2%;
}

.column:first-child {
  margin-left: 0;
}

/* Clearfix: I really like naming this 'group' when 
working with grids, as that tends to be what we are 
actually using it for in almost all cases */

.group:after { 
  content:"";
  display:table;
  clear: both;
}
.group {
  zoom:1;
}

To get the subdivisions for our columns we'll do some really simple calculations:

w = full width / # of columns
  = 100 / 8
  = 12.5
  
m = %margin / # of columns
  = 2 / 8
  = 0.25
  
subdivision = w + m
            = 12.75%

Now starting from 100% we just subtract this subdivision repeatedly, so in this case taking away 12.75% from our width each time:

Style.css

/* Our 8 column grid */
.eight_col {
  width: 100%;
}
.seven_col {
  width: 87.25%;
}
.six_col {
  width: 74.5%;
}
.five_col {
  width: 61.75%;
}
.four_col {
  width: 49%;
}
.three_col {
  width: 36.25%;
}
.two_col {
  width: 23.5%;
}
.one_col {
  width: 10.75%;
}

And voila, all we have to do is add any custom breakpoints and behaviour that we want with media queries, to handle when the user's screen size is adjusted. So for example if we wanted to swap to full width on mobile:

Style.css

/* Full width below 480px */
@media only screen and (max-width: 480px){
  .column {
    float: none;
    margin-left: 0;
  }
  .eight_col, .seven_col, .six_col, .five_col,
  .four_col, .three_col, .two_col, .one_col {
    width: 100%;
  }
}

And now you've got yourself a fully working responsive grid that you can add to your websites, all with just a few lines of CSS and some simple math. So if you ever find yourself reaching for a hefty framework that you don't really need, or you want to build a more highly customized grid, consider building it yourself; it's much easier than it may seem.

-Brad 

Building an API with Node.js and MongoDB

Building an API with Node.js and MongoDB

When building a new application an important consideration is often the platform you'll be releasing it on. Back in the old days these would largely have to be built and managed separately, but in the last half-decade or so a number of better options have become available to us. One of the most common techniques is the use of a JSON API (Application Programming Interface). Using the web to serve up JSON documents rather than HTML documents allows us to directly deliver the data that we need to build the components of our applications, or to allow other developers to build applications using our services.  

Today we're going to take a look at how to build an API of your own using Node.js, Express and MongoDB. For the database in the examples I'll be using mLab, but you can use any instance of a Mongo database you like, in fact with some edits you can really use any data storage method that you like. API's are as flexible as any code and largely agnostic about where and how we store our data, instead being primarily concerned with how to respond to the requests that we make of it, we'll be using MongoDB & mLab largely out of convenience for style and formatting. 

On a final note, testing an API, especially if you haven't done so before, is a little different than what you may be used to. Since our requests are typically being sent through form data or through the header, having a convenient way to test that they are working as intended without extra code and legwork often requires specialized tools. The most thorough of these is probably the Postman web extension, which I highly recommend for work with API's and web services. 

Alright lets dive in, we're going to be creating a project structure like so:

So an app directory with two sub-directories models and routes, and four files; our user.js model, the routing file route.js, our package.json file and the server.js file that we will use to launch the application.

Let's set up the package.json first, as it's really simple in this instnace.

package.json

{
  "name": "simple-api",
  "main": "server.js",
    
  "dependencies": {
    "express": "~4.0.0",
    "mongoose": "^4.4.6",
    "body-parser": "~1.0.1"
  }
  
}

We're going to be using three packages: 

  • The express framework to handle our server, routing and requests / responses.
  • Mongoose, which will help us with our MongoDB object modelling.
  • body-parser, which we will use to parse and handle our JSON.

The versions used here aren't that big of a deal, they were simply the most recent at the time of writing, you can feel free to npm install express mongoose body-parser --save

Let's take a look at our user model next.

user.js

// Set up mongoose and mongoose.Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

// Export our mongoose model, with a user name and friends list
module.exports = mongoose.model('User', new Schema({
    name: String,
    friends: [String]
}));

This is also as straightforward as you can get, we're creating a basic user schema that gives each user a name of type String and a list of friends, which we've defined as an Array of Strings.

The route.js file is where the bulk of the application is going to be. We're going to build a simple RESTful service using standard verbs that lets us GET users, DELETE users, create new users through POST requests and update users through PUT requests. We're also going to take a look at some of the hiccups that can occur if you don't spend a little time understanding the architecture of your API beforehand. 

I'm going to heavily comment the route.js file to help explain everything that's going on in there.

route.js

// Set up express and include our User model
var express = require('express');
var User = require('../models/user');

// Get an instance of the express router
var router = express.Router();



// Our first set of routes, those that end with /users
router.route('/users')

/*
// When we POST to the /users route we want to create 
// a new user from the data sent in the request. We're 
// going to assume that our new users come packaged with 
// a friend (a la MySpace Tom), though we could easily 
// initialize this to an empty array as well.
*/
.post(function(req,res){

    var user = new User();
  
    // Set the user name, and add our friend to the friends array 
    user.name = req.body.name; 
    user.friends.push(req.body.friends); 

    // Save the user to the database
    // If we don't get any errors respond with a success message
    user.save(function(err){
        if (err) { res.send(err); }

        res.json({ message: 'We have created a new user!' });
    });
})

/* 
// When we make a GET request to /users we want 
// to return all of our users in the response as 
// a JSON object.
//
// We'll use mongoose to find our user documents, 
// and if there are no errors, we'll send a response 
// containing our users as JSON
*/
.get(function(req,res){

    User.find(function(err, users){
        if (err){ res.send(err); }

        res.json(users);
    });

})



// Routes for a specific user, ending in /users/:user_id
router.route('/users/:user_id')

/*
// When we make a GET request for a specific user,
// we want to return that user as a JSON object.

// We'll use mongoose to find our user by their id, 
// and if there are no errors, we'll send a response 
// containing our user data as JSON

// As a side note, you may have noticed that we didn't
// create a user_id parameter in our schema, this parameter
// is automatically uniquely assigned by MongoDB. We can use 
// our own unique keys if we so choose.
*/
.get(function (req,res){

    User.findById(req.params.user_id, function(err, user){
        if (err){ res.send(err); }

        res.json(user);
    });
})

/*
// When we make a PUT request we want to update 
// the user with the specified id using the data 
// in the request, if there are no errors we'll 
// respond with a success message.
*/
.put(function(req,res){
    User.findById(req.params.user_id, function(err, user){
        if (err){ res.send(err); }

        user.name = req.body.name;
        user.friends.push(req.body.friends);

        user.save(function(err){
            if (err) { res.send(err); }

            res.json({ message: 'User Updated!' });
        });
    });
})

/*
// When we make a DELETE request we want to 
// remove the user with the specified id, if 
// there are no errors we'll again respond 
// with a success message
*/
.delete(function(req, res){
    User.remove({_id:req.params.user_id}, function(err, user){
        if (err){ res.send(err); }

        res.json({ message: 'Successfully removed!' });
    });
})


module.exports = router;

In essence, this file is really just handling what we do with traffic that we receive to the given routes. Based on the requests we send we may make changes to our database, serve up the specific data being requested, or send standardized messages that can be processed by event handlers to tell other parts of the application what is going on. It's the core of our API. 

Finally let's take a look at the set up for a basic server.js file to launch our application.

server.js

// Set up our packages
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var apiRoute = require('./app/routes/route');

// Connect to our database
mongoose.connect('mongodb://USERNAME:PASSWORD@ds019638.mlab.com:19638/DBNAME');

// Configure body-parser
app.use(bodyParser.urlencoded({ extended:true }));
app.use(bodyParser.json());

// Set our port
var port = 8080;

// Prefix our routes with with /simple-api
app.use('/simple-api', apiRoute);

// START THE SERVER
app.listen(port);

So everything here is looking pretty good. We're making use of the standard GET, POST, PUT and DELETE, handling our incoming requests and responses, and taking care of data storage and persistence with MongoDB and mLab. However, this example highlights a problem that slipped in, what happens if we want to remove a friend from our friend list? Our PUT request, as it stands, is poorly structured. On submission it seems that it takes a user name and a friend (or a user name and an empty friend) and then updates our object, but this is extremely limited.

We could adjust the way that we are assigning values to the friends property. Instead of pushing individual friends to the array as we receive them, we could add a logic layer that builds a new array from our current friend list and the data in the request and subsequently have our PUT method reassign the entire array each time. This would likely be best for this simple situation, but we still potentially have a broader issue. In short, what do we do if we want to do a partial or specific update to some of the data in an object, rather than all of it at once?

We could solve this in a few different ways, and this is where the individual architecture of different API's comes into play, depending on what is required for the service that you are building. A common technique is to extend the actual API endpoint, so rather than having our request go through /users/:user_id, we go down to the individual property, /users/:user_id/friends, and build unique GET, PUT and DELETE methods specifically for that property and route. This allows us to do partial updates on our documents for any properties that we find may be frequently updated, but it comes at a cost. As the application grows you can potentially have hundreds of these fine grain elements, all with their own methods and handlers, and without some kind of code generation or scaffolding this can get out of hand quick. There are a few other techniques that can alleviate the partial update issue, I would recommend this blog post for a good succinct look at their pros and cons. 

Other than that, putting together an API really is just a matter of proper route handling and building the basic functionality to respond to requests that those routes receive. Whether that means adjusting something in the model, serving up some data to be consumed elsewhere in your app, on a different platform, or by a different developer. It is a very flexible means to build unique, useful and valuable applications across all media.

-Brad

Testing Javascript with Jasmine - Part II

Testing Javascript with Jasmine - Part II

Last time we took a quick look at setting up Jasmine, one of the popular testing frameworks for Javascript, in your Node project. Today we're going to go a bit deeper on how tests are written and how to handle things like asynchronous behaviour. This one might get a little lengthy, so lets jump right in.  


Let's start off with a simple sample test suite, to get a bit of a feel for how we write tests with Jasmine. Test suites in Jasmine are defined with the describe keyword, and take two parameters, a String for the suite name and a function to implement it. Within the describe blocks our individual tests are implemented with the it keyword. It similarly takes a String, which defines the spec name, and a function where we implement the logic for our test. Jasmine comes packed with a lot of matchers that we can make use of in our test cases, let's check out a few of them below:

userSpec.js

describe("User Suite", function() {

  
// ====================
// A bit of set-up
// ====================
  
  var user = {
    name: 'Santa Claus',
    location: 'North Pole',
    favoriteThings: ['Milk', 'Cookies', 'Rudolph'],
    setLocation = function(value){
        location = value;
    }  
  };
  
  beforeEach(function() {
    spyOn(user, 'setLocation').and.callThrough();
    setLocation('Canada');
  });       


// ====================
// Our tests
// ====================

  it("Should exist", function() {
    expect(user).toEqual(jasmine.anything());
  });
  
  it("Should have a user named Santa Claus", function() {
    expect(user.name).toBe('Santa Claus');
  });
  
  it("Should have Cookies as one of the favoriteThings", function() {
    expect(user.favoriteThings).toContain('Cookies');
  });
  
  it("Should not have a property dislikesChildren", function() {
    expect(user.dislikesChildren).toBeUndefined();
  });

  it("Should be able to call its functions", function() {
    expect(user.setLocation).toHaveBeenCalled();
  });

  it("Should have a working setLocation function", function() {
    expect(user.location).toBe('Canada');
  });
  
});

The full list of matchers can be found in the Jasmine Documentation, a few we're highlighting here include: 

.toEqual()

Typically used to check simple literals and variables, it can also be used to check for object equality between two objects. Here we are making use of the special jasmine.anything(), which will return true if the actual value is anything other than null or undefined, to check the existence of our user object.

.toBe() 

Makes use of '===' under the hood to check equality between the expected value and the actual value.

.toContain() 

Checks the contents of an Array to find if the expected value is contained in that array, returns true if it's found.

.toBeUndefined()

Will return true if the value is undefined, like in our case, looking for an incorrect property on an object.

.toHaveBeenCalled()

One of the many uses of function spies, will return true if the provided function was called during program execution. This includes calls to the double of that function. As a side note, the .and.callThrough() method is important to include on our function spies if we are testing the functionality of a particular call, it indicates to Jasmine to go ahead and execute the actual function we're referencing, rather than the double. If for example our beforeEach function omitted the call through:

beforeEach(function(){
  spyOn(user, 'setLocation');
  setLocation('Canada');
});

Then our final test case, 'Should have a working setLocation function', would fail, Jasmine creates a double of the function to test against, not the actual function itself and our location would remain 'North Pole' rather than 'Canada'.


So simple instances where we have control over the program flow are all well and good, but what about when we have to deal with asynchronous behaviour? Lets say for example we aren't using a direct user object like we have above but are instead making an API call to pull that data object from another source.  

var user = {};
user = someApiCall();

If there is a delay on when we get the data to populate our user object, Jasmine is going to start throwing a lot of test failures when it just keeps chugging along rather than waiting for our API response. Thankfully there is a solution to this, the special callback done(). It will indicate to Jasmine that it should wait (by default 5 seconds, though you can adjust this if need be) for our spec to finish before it throws any errors. Let's take a look at an example with promises:

describe("Async User Suite", function () {
  
  var user = {};

  beforeEach(function (done) {
    $.getJSON("http://localhost/8080/api/users/")
    .done(function (result) {
      user = result;
      
      // Invoke Jasmine's done callback
      done();
    });
  });

  it("Should have our user object", function () {
      expect(user).not.toBeUndefined();
      expect(user.name).toBe('Santa Claus');
  });

});

This time, assuming our API doesn't take forever, our tests will succeed. We are using jQuery for our promises, but you can use any method you'd like, the important element is to invoke done() when you are finished with your data / are at the point where you want to test. There is actually a bit of a gotcha using the jQuery method in that the success method for $.getJSON is also named done, the .done(function (result){ ... }); method above. Just something to watch out for.

The last thing that could probably use mentioning is actually running our tests. You can run your test suites simply by running jasmine from the command line in the root directory of your project. You can also give it a relative path to the suite you wish to run if you have a larger test set and don't want to run them all. For example: jasmine spec/userSpec.js will just run our userSpec file. Plugins are available for all major task-runners and bundlers like Grunt, Gulp and Webpack to help with automating this as well. 


And that's our overview of Jasmine, a relatively simple yet powerful library for testing your Javascript. Next up is another two-parter (maybe three depending on how large it gets) on building an API using Node.js and MongoDB to add a little cross-platform data freedom to your projects. 

-Brad

Testing Javascript with Jasmine - Part I

Testing Javascript with Jasmine - Part I

Today we're going to take a really quick look at setting up the Jasmine testing library for Javascript. Jasmine is a behaviour driven development framework, usually abbreviated BDD, and essentially means that we are using natural language to describe our tests and their expected results. 

The first thing that we're going to want to do is install Jasmine and its CLI tools.

npm install -g jasmine

Now inside your project directory you can create a simple test folder and configuration file.

jasmine init

Cool. Now we should have a spec folder to place our test files and a basic jasmine.json config file, which we'll take a look at below. 

jasmine.json

{
  "spec_dir": "spec",
  "spec_files": [
    "**/*[sS]pec.js"
  ],
  "helpers": [
    "helpers/**/*.js"
  ],
  "stopSpecOnExpectationFailure": false,
  "random": false
}

This file is giving us a few things, the directory for our files (in this case spec), the general names of our test files (anything that ends with spec.js or Spec.js, for example, storeSpec.js), and the location of our helper files, which we can use to define custom matchers. 

The final two lines are options we can make use of to either pseudo-randomly execute our tests cases, or, in the case of stopSpecOnExpectationFailure, to immediately stop our tests upon the first failure that we find. Both of these can also be set as CLI options using --random=false and --stop-on-failure=false respectively. 

On the matter of CLI options there is another one that is pretty useful and you can find yourself using fairly often, it's the --filter option. This will let you filter and run only the given spec, so for example, --filter="should be possible to add an item to the cart", will only run the spec with the given description. 

Though less common, Jasmine can also be used as a library directly in your project, lets take a look at a simple example of this.

var Jasmine = require('jasmine');
var jasmine = new Jasmine();

jasmine.loadConfigFile('spec/support/jasmine.json');

jasmine.execute();

Here we are making use of the CommonJS syntax (though you can use whichever module syntax you prefer) to import Jasmine. The loadConfigFile property gives the path to our Jasmine config file and the .execute() function will run it. Simple as that. 

Next time, in the heftier part II, we'll dive into test writing with Jasmine's describe and it blocks, and how to handle common issues like asynchronous behaviour. 

 

-Brad

Styling React Components Through State

Styling React Components Through State

React applications, with all their DOM manipulation and re-rendering, give us a pretty good environment to do things like add and remove class names to apply style changes to our app. In this post we'll take a look at two methods of doing just that. In the first method we'll simply be doing everything ourselves, and in the second we'll be making use of the officially supported Classnames utility. This isn't exhaustive by any means, but it is a good example of how our application state and styles can interact.


The Do-Everything-Ourselves Method

We're going to make an awesome square that turns into a circle when we click on it, then back to a square if we click again. Internet magic at its finest. Let's write some simple css rules for our square, and a general transition rule for the animation.

.square {
  width: 200px;
  height: 200px;
  border-radius: 0%;
  background-color: blue;
  transition: all 0.5s ease-out;
}

Cool. Now let's build the React component for our square.

import React from 'react';

class CoolSquare extends React.Component {
    constructor(props){
        super(props);

        this.state = {
            isClicked: false
        };
    }

    render() {

        var classLabel = "square";
        if(this.state.isClicked == true){
            classLabel += " active";
        }

        return (
        <div className={classLabel} 
          onClick={() => this.itWasClicked}>
        </div>
        );
    }

    itWasClicked(){
        this.setState({isClicked: !this.state.isClicked});
    }

}

export default CoolSquare;

So here we've created a CoolSquare component and given it a property isClicked that we have initialized to be false. Next we're creating a classLabel variable for the square that will conditionally handle our class names through an if statement: if isClicked is false we have the default 'square', and if it's true we have 'square active'. Next we return our div, with the corresponding classLabel giving the element its class. Lastly we have the addition of an event handler to the element that will trigger a state change when it has been clicked, flipping the isClicked property between true and false. This is the really useful bit.

Thanks to the way React handles state, any change in the state of our component (like that click event) will trigger a re-render of our app, giving us the classLabel for the current state of the square and in turn the appropriate class name for its element. So all we have to do now if we want to make that square a circle when we click on it, is add a border-radius rule for 'square active'.

.square.active {
  border-radius: 50%;
}

And voila, we've got our dynamic classes doing their thing.


The Classnames Utility Method

So while in our simple example doing this ourselves isn't that painful, real-world applications are typically going to have more than one element, more than one potential state and added conditional logic. The suggested way to work with this extra complexity is a javascript package called Classnames. It gives you the use of a classNames function that will take any arbitrary number of string or object arguments, and output only those which are truthy. So rather than writing if statements for each class condition we want to check, we can represent them directly as an object. 

To borrow an example from the Classnames documentation, let's say we are building a button component, and we want this button to be as versatile as possible because we're using it all across our app. We may have states for if the button is clicked, if it's hovered, an un-clickable state while our app processes something, an error state, a flashing strobe-light state and so on. Again, rather than writing repeated if statements, Classnames allows us to do the following:

import React from 'react';
import classNames from 'classnames';

class CoolButton extends React.Component {
  
  // ...
  
  render () {
    var classLabel = classNames({
      'btn': true,
      'btn-clicked': this.state.isClicked,
      'btn-hover': this.state.isHovered,
      'btn-process': this.state.isProcessing,
      'btn-strobe-lights': this.state.isStrobeLightTime
    });
    
    return (
      <button className={classLabel}>Click Me!</button>
    );
  }
}

export default CoolButton;

Now our classNames function will evaluate and return only those properties whose current state is true, allowing us to easily build our classLabel. This gives us the flexibility to handle much more complicated cases (you can add whatever logic you'd like to evaluate a class name), while still expressing them simply. 

We can actually take this whole styling components through state one step further with something like Radium, but I'll save that for another time. 

 

-Brad

Getting a simple React app on Heroku

Getting a simple React app on Heroku

*This post was updated in April 2016 to reflect changes to Babel and the Webpack config

 

When I first started learning Facebook's React.JS library there were a couple things that threw me for a loop. First was the use of JSX, and its movement away from the .html, .css, .js separation of concerns that I knew and loved in exchange for a more component based separation. But like most React folks I quickly came around to this way of thinking. After all, very often our code was intrinsically tied together anyway, we were just putting it in separate files. The second thing that threw me off was a bit more unexpected, after going through a few initial tutorials I realized I didn't actually know how to get a React app online in a production environment. 

Coming from a background in Rails and similar frameworks, which often have a very well defined pipeline for deployment, I quickly found that React is completely agnostic about the matter. Not only that, but a few Google searches showed the number of different approaches that you could take was staggering. Much of this stems from the fact that React simply compiles to javascript, and there are so many different options out there to help you build, bundle and serve up your javascript assets. 

I eventually settled on a simple workflow using Express and Webpack to get my React apps online, with the wiggle room to add complexity over time if need be.

We're going to be adding / editing four files in the root directory of our project:

  • Our package.json file
  • Our Webpack configuration file, webpack.config.js
  • A simple Express server, that we'll name server.js
  • A procfile for Heroku

Let's start by setting up our package.json file. If you're new to things like Node and are coming from something like Rails, this is the rough equivalent of your gemfile, with a few extra bells and whistles. You can build this manually or by running npm init from the command line of your project directory.

Package.json

{
  "name": "simple-heroku",
  "version": "1.0.0",
  "description": "Our simple set up for React on Heroku",
  "main": "index.js",
  "repository": "",
  "scripts": {
    "start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js",
    "prod": "NODE_ENV=production node server.js",
    "postinstall": "webpack -p"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "babel-core": "^6.2.1",
    "babel-loader": "^6.2.0",
    "babel-preset-es2015": "^6.1.18",
    "babel-preset-react": "^6.1.18",
    "webpack": "^1.12.9",
    "express": "^4.13.3",
    "react": "^0.14.3",
    "react-dom": "^0.14.3"
  }
}

A few different things are happening here. First off you may have noticed that we have three scripts, 'start', 'prod' and 'postinstall'. Each of these is short-handing some command line code. 'Start' will fetch and run our dev-server when we npm start, 'prod' will let us test our production build locally with npm prod by running our server.js file, and lastly the postinstall script will run automatically after our packages are installed, using webpack to build a bundle.js file that we'll get into in a minute. 

The second half of this file is where we list our project dependencies, in this simple example we're making use of webpack, express, react, and I've added babel to support ES6 syntax and give an example of how webpack loaders work. The versions are simply those available at the time of writing.

Speaking of Webpack.


Webpack.config.js

module.exports = {
  entry: [
    './src/index.js'
  ],
  output: {
    path: __dirname,
    publicPath: '/',
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      query: {
        presets: ['es2015', 'react']
      }
    }]
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  }
};

Webpack is a module bundler that is very versatile and works well with React. That being said it has a pretty steep learning curve. This is the section where you probably have the most leeway to use whichever tool works best for you, Browserify is another common choice, there are options to use things like Grunt and Gulp as well. We'll stick with Webpack here for now.

So what's going on is that messy looking file above? It's actually relatively straightforward. We're providing the path to the javascript file that serves as the entry point to our React application, in this case an index.js file, along with an output file name and directory (bundle.js building right to the root). 

The second thing that's happening, is we're running something called the babel-loader. This is a build step that will make use of Babel to convert our ES6 & JSX to browser-compatible ES5. We're making use of the two presets we installed babel-preset-2015 and babel-preset-react to get this done. There are a lot of different loaders and ways that you can chain them together to create the build process you are looking for, including things like CoffeeScript, SASS, and Jade but it's definitely beyond the scope of this post. You can check out more in the documentation

The last line is for a bit of convenience in our code, resolve allows us to shorten our files when using require. So we can require('fileName') vs require('fileName.jsx')


Server.js

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/'));

app.listen(process.env.PORT || 8080);

This is a bare-bones Express server that we're putting together to serve up the static assets in our root directory. If you are building your app to a different directory, you can feel free to serve up that one instead. For Heroku purposes, the most important line of this file is the last one. We're telling our app that if you are being given the environment variable PORT, which is provided by Heroku, use it. If we don't have this variable then go ahead and use port 8080.


The final thing that we're going to need is a procfile for Heroku, telling it how to handle the web requests that come through. In our case we just need to run our server.js file and our set-up will take care of the rest, so this is a simple one-liner.

Procfile

web: node server.js

And that's it, now when we git push heroku master, our app should be online and good to go!

 

-Brad