React Hooks

I learned a really cool way to streamline and reuse API logic in my React components by leveraging React Hooks. Hooks let you use state and other React features like lifecycle without building classes and using non-descriptive methods like setState() and componentDidMount(). And fear not, Hooks are backwards-compatible, so you won’t break any code by using them, nor do you have to use them because React has no plans to phase out classes.

According to the docs:

Hooks don’t replace your knowledge of React concepts. Instead, Hooks provide a more direct API to the React concepts you already know: props, state, context, refs, and lifecycle.

To demonstrate how hooks can streamline your API logic and make it super descriptive, we’ll be using two: useState and useEffect. Both hooks are functions that let you “hook into” React state and lifecycle features from function components. They dramatically streamline keeping track of state and lifecycle and let us be extremely specific about our logic.

Before hooks, we would build a class like DataFetcher and use componentDidMount() to handle the request and its side effects:

import React, { Component } from "react";
export default class DataFetcher extends Component {
state = { data: [] };
componentDidMount() {
fetch("https://data.cityofchicago.org/resource/ydr8-5enu.json?")
.then(response => response.json())
.then(data =>
this.setState(() => {
return { data };
})
);
}
render() {
return this.props.render(this.state.data);
}
}

view raw

.jsx

hosted with ❤ by GitHub

And then we’d somewhat cumbersomely consume the component by passing it a render prop:

<DataFetcher
render={data => {
return (
<div>
<ul>
{data.map(el => (
<li key={el.id}>{el.title}</li>
))}
</ul>
</div>
);
}}
/>

view raw

.jsx

hosted with ❤ by GitHub

That approach is fine but it has its shortcomings. 1) We have to use a class. 2) We have to use non-descriptive methods like setState() and componentDidMount(), and  3) we have to pass a render prop every time we consume the component class.

Seems like this stuff should be under the hood. Hooks to the rescue. In the following example, I import useState and useEffect hooks, which keep track of state and lifecycle respectively. With these nifty shortcut functions, we can now encapsulate the API call in a reusable function:

// fetchData.js
import { useState, useEffect } from "react";
export default function fetchData(url) {
const [data, setData] = useState([]);
useEffect(() => {
fetch(url)
.then(response => response.json())
.then(data => setData(data));
}, []);
return data;
}

view raw

.jsx

hosted with ❤ by GitHub

According to the docs, “useState returns a pair: the current state value and a function that lets you update it. You can call this function from an event handler or somewhere else.” Nifty huh? This lets us be way more descriptive. We can call setData() instead of setState().

Likewise, with useEffect() we can encapsulate our API call’s side effects in a descriptive, reusable function instead of wrapping it inside the generic componentDidMount()  which only tells us about lifecycle, not what we’re actually doing.

And then we can consume it in any component we want without the need to pass it render props.

import React from "react";
import fetchData from "./fetchData";
export default function permitList(props) {
const data = fetchData("https://data.cityofchicago.org/resource/ydr8-5enu.json?&quot;);
return (
<div>
<ul>
{data.map(el => (
<li key={el.id}>{el.permit_type}</li>
))}
</ul>
</div>
);
}

view raw

.jsx

hosted with ❤ by GitHub

Thanks to React hooks we now have a really beautiful way to make our code easy to read and understand. Hooks let us be better stewards of the codebase so future devs can jump right in.

omg polymorphic associations

Don’t worry, they really aren’t that scary, but it’s the sort of concept that slips away from you if you haven’t worked with it in a while. For a recent code challenge, I was asked to find a polymorphic use case for the upvotes table in my Graffito app. Currently, the table functions as a join between the user and graffiti models. There is a many-to-many relationship between users and graffiti and upvotes is the glue that binds them. The association declarations and schema look like this:

# user.rb
class User < ActiveRecord::Base
has_many :upvotes
has_many :graffiti, through: :upvotes
end
# graffiti.rb
class Graffiti < ActiveRecord::Base
has_many :upvotes
has_many :users, through: :upvotes
end
# upvote.rb
class Upvote < ApplicationRecord
belongs_to :user
belongs_to :graffiti
end
# schema
create_table "upvotes", force: :cascade do |t|
t.integer "user_id"
t.integer "graffiti_id"
t.timestamps
end

This is fine so long as we only want to allow users to upvote one model, Graffiti. But what if we expand that feature to favorite specific photo uploads that belong to a graffiti? At first glance, it might appear that a new upvotes tables is required: upload_upvotes. But that instinctually feels like overkill and a violation of the DRY principle.

How can we extend the upvotes table to handle relationships to not only graffiti but also uploads? Polymorphic Associations to the rescue.

According to Rails docs, “with polymorphic associations, a model can belong to more than one other model, on a single association.” This is achieved by abstracting the association naming more broadly, often just by adding able to the join model name, i.e., upvotable. Let’s take a look at the new associations and schema:

# graffiti.rb
class Graffiti < ActiveRecord::Base
has_many :uploads
has_many :upvotes, as: :upvotable
end
# upload.rb
class Upload < ApplicationRecord
belongs_to :user
belongs_to :graffiti
has_many :upvotes, as: :upvotable
end
# upvote.rb
class Upvote < ApplicationRecord
belongs_to :user
belongs_to :upvotable, polymorphic: true
end
# schema
create_table :upvotes do |t|
t.integer :user_id
t.integer :upvotable_id
t.string :upvotable_type
t.timestamps
end

On line 16 above, we establish a polymorphic association, upvotable, which translates to two new columns in the upvotes table, upvotable_id and upvotable_type. Upvotes can now belong to more than one model on the single association; upvotable functions as an alias to any other model we attach it to, e.g., graffiti and uploads.

There’s one more thing I want to unpack. A user has many upvotes. But upvotes now attached to multiple models so we have to devise away to query the graffiti or uploads that users have upvoted. Once again we can take advantage of our polymorphic association and simply specifiy that source types we’re interested in (Graffiti and Uploads).

class User < ActiveRecord::Base
# …
has_many :upvotes
has_many :graffiti, through: :upvotes, source: :upvotable, source_type: "Graffiti"
has_many :uploads, through: :upvotes, source: :upvotable, source_type: "Upload"
# …
end

view raw

user.rb

hosted with ❤ by GitHub

The great thing about polymorphic associations is that they scale really well. Imagine we decide to add upvotes to comments, drawings, or videos. That’s not a problem. The upvotes table can be extended to handle any number of models on our single abstract association, upvotable, and we don’t have to worry about managing a bunch of other upvote tables. Polymorphic associations are efficient and elegant if not a little confusing. They are well worth the effort.

Refactoring with let Block Scope

While I was refactoring a code challenge today, I learned something very cool about ES6 variable declarations via the let keyword vs. variable declarations via the var keyword. let is scoped to the nearest block while var is scoped to the nearest function. This is particularly important in the context of loops because let will create a new binding of a variable for each iteration; var will only create one binding.

When you have a callback inside a loop that relies on separate bindings at each step, using let saves you the headache of wrapping the callback in a closure to make copies of the variable at each increment. The canonical example is calling JavaScript’s setTimeout() function inside a loop to execute a function or code snippet after a specified period of time (delay) in milliseconds:

// prints '5' 5 times
// yikes that's not what we want
// the code runs so fast and creates only one binding of i equal to its last value, 5
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// solution 1: pass setTimeout a callback with arguments
// caveat: only modern browsers support the third argument
// prints 0, 1, 2, 3, 4
for (var i = 0; i < 5; i++) {
setTimeout(print, 1000, i);
}
function print(i) {
console.log(i);
}
// solution 2: wrap SetTimeout in a closure
// works in all browsers
// prints 0, 1, 2, 3, 4
for (var i = 0; i < 5; i++) {
handleTimeout(i);
}
function handleTimeout(i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// solution 3: ES6 to the rescue! just use 'let'
// prints 0, 1, 2, 3, 4
for (let i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}

view raw

letVsVar.js

hosted with ❤ by GitHub

Let’s take a look at how this informed the refactoring of my code.

I was tasked with building a tool that takes a sequence of CSS styles as input and uses vanilla JavaScript to apply each step in the sequence to the DOM, animating an element over time.

The input consists of a 2D array of CSS styles, where each array has a time delay and any number of style objects.

input: [
[100, { width: "10%" }],
[200, { width: "20%" }],
[200, { width: "50%" }],
[200, { width: "80%" }],
[300, { width: "90%" }],
[100, { width: "100%" }]
]

view raw

input.js

hosted with ❤ by GitHub

To implement the animator, I looped over the input and set timers to update the style of an element in the DOM after a delay. let‘s block scope binding allowed me to refactor my code without a closure.

// In the initial code, I wasn't aware that let would create a new binding for
// each variable inside my loop. I assumed a closure around the setTimeout function
// was necessary to create new copy of the variables at each step.
animate() {
let previousDelay = 0;
let styles = null;
for (let sequence of this.dataSet) {
let delay = sequence[0] + previousDelay;
let objects = sequence.filter(this.isObject);
styles = this.formatStyles(objects);
this.handleTimer(delay, styles);
previousDelay = delay;
}
styles;
}
handleTimer(delay, styles) {
let timerID = setTimeout(() => {
console.log(delay);
this.element.style = styles
}, delay);
return timerID
}
// In the refactored solution, I realized the closure was superflous
// double yay, let = concise code
animate() {
let delaySoFar = 0;
let styles = null;
for (let sequence of this.dataSet) {
let delay = sequence[0] + delaySoFar;
let objects = sequence.filter(this.isObject);
let styles = this.formatStyles(objects);
setTimeout(() => {
this.element.style = styles;
}, delay);
delaySoFar = delay;
}
styles;
}

An integral part of the challenge is that each step is relative to the previous step. So it’s not enough to apply the styles at step 2 after 200 milliseconds (see input array above); step 2 must be applied after delay + delaySoFar milliseconds, or 300 milliseconds. Likewise, step 3 must be applied after 500 milliseconds.

To persist the cumulative delay, on line 29 above, I declare the variable delaySoFar outside of the loop. Inside of the loop, I set each step’s delay to the sum of the current delay (sequence[0]) and delaySoFarOn line 36, I invoke setTimeOut(), without a closure thanks to let‘s block scope binding. Inside each timer, I set the style of an element in the DOM after the current delay. Last, after the timer is set but before the next loop, I update delaySoFar. The result animates the element and each step’s delay is relative to the previous step.

I really enjoyed this code challenge. The efficiency of let‘s block scoping is nifty.

Some More Thoughts on React

I’ve been immersed in React for about three weeks now, and so far I’m finding it really easy to organize and maintain. Compared to Angular 1 (still haven’t tried Angular 2), my code is also much easier to read and understand. I like how JSX lets me embed HTML-like syntax inside JavaScript, instead of having separate HTML templates with Angular’s unique syntax embedded within. With React, you don’t have to learn all that new syntax.

An all-JavaScript approach not only feels intuitive but it has performance benefits. React achieves this by decoupling state from the DOM and storing it in a virtual DOM. When state lives in the real DOM you must traverse a sometimes huge tree structure to update a node (think jQuery), whereas with React’s virtual DOM, it keeps an eye on the state of a component via a diff algorithm, and whenever it changes, it simply converts the component to a React element and inserts it in the DOM. Imagine a DOM with thousands of child nodes – the virtual DOM approach results in far greater efficiency.

Furthermore, the idea of designing a code base in terms of reusable UI components instead of a larger MVC framework vis-a-vis Angular 1, cuts down significantly on my code base. Its principles encourage me to think more about the features and layout of my site.

Most important, I love the React environment. With webpack and the webpack-dev-server, debugging is a synch because it happens in real time; the server watches your source files and recompiles them whenever there is a change. If there’s a bug, the app will break and almost always yield a helpful error message because React is all JavaScript. On the other hand, because Angular embeds its own syntax in HTML templates, debugging can be more difficult.

I also love the object-oriented approach that React encourages. With ES6 classes, I can define state and the events that change it in the constructor of my component. That makes the code more succinct and maintainable for a colleague who might jump in on a project. Here’s an example of an ES6 class with a constructor function from a current project I’m working on:

import React from 'react'
import Prompt from '../components/Prompt'
class PromptContainer extends React.Component {
constructor(props) {
super(props)
this.state = { username: '' }
this.handleUpdateUser = this.handleUpdateUser.bind(this);
this.handleSubmitUser = this.handleSubmitUser.bind(this);
}
// …
}

Lines 7-9 above demonstrate how quickly one can get up to speed on what this component is responsible for: keeping track of a username in the DOM. Line 7 signifies that the username property is what we are watching. Line 8 tells us that there is an event that updates that property while line 9 shows there is a form submission event. A fellow developer jumping into this code would be off to a great start synthesizing its purpose. On a side note, it’s important to note that we must call .bind and pass in this on both of our events; otherwise this will be undefined in the method.

Let’s talk about line 5 as well. All React classes are initialized with a props object via calling super(props). Don’t be sidetracked by the super part. The only effect of calling super on props is so you can access this in the constructor. It’s probably redundant because we already have reference to props but the React docs encourage it: “Class components should always call the base constructor with props,” which is in keeping with object-oriented JavaScript’s standard of binding instance properties to this.

The props object allows you to access anything you pass in while “invoking” a component. Because I’m using React Router, my props object contains all sorts of useful information like routes, route params, and location, plus anything else I want to pass when I invoke the component.

Let’s take a look at my routes and compare it with the props object it yields.

import React from 'react'
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
import App from '../components/App'
import Home from '../components/Home'
import PromptContainer from '../containers/PromptContainer'
module.exports = (
<Router history={hashHistory}>
<Route path='/' component={App}>
<IndexRoute component={Home}></IndexRoute>
<Route path='playerOne' header='Player One' component={PromptContainer} />
<Route path='playerTwo/:playerOne' header='Player Two' component={PromptContainer} />
</Route>
</Router>
)

view raw

routes.js

hosted with ❤ by GitHub

On line 11, I “invoke” a route component and pass it three key/value params: path=’playerOne’, header=’Player One’, and component={PromptContainer}. component points to the class where all this information is headed.

Now, inside the constructor of PromptContainer, let’s log the props object to the console. A lot of useful information lives in props when you use React Router, but lets focus on what we manually passed in. The route object contains all the info we passed in and we can now access by call any of the keys on this.props.route.

screen-shot-2017-01-13-at-11-19-08-am

Finally, let’s demonstrate how we can use props, state, and the events defined in our constructor in the render method of our UI component:

function Prompt(props) {
return (
<h1>{this.props.route.header}</h1>
<div className="col-sm-12">
<form onSubmit={this.onSubmitUser}>
<div className="form-group">
<input
className="form-control"
placeholder="Github Username"
type="text"
onChange={this.onUpdateUser}
value={this.state.username} />
</div>
<div className="form-group col-sm-4 col-sm-offset-4">
<button
className="btn btn-block btn-success"
type="submit">
Continue
</button>
</div>
</form>
</div>
);
}

view raw

prompt.js

hosted with ❤ by GitHub

On line 3, we access our header prop as the value of our tag. Line 5, binds the onSubmitUser event to the React onSubmit callback. Line 11 binds our onUpdateUser event to React’s onChange event (this watches for any changes to the input field). Last, on line 12 we set the initial value of the input field to the state of username defined in the constructor.

Check out this codepen to see a working example. Note that the app is incomplete. After you enter player two’s name, an alert will flash.

Functional React Components and Props

In this post, I’ll show how to build an avatar using functional React components. You can think of React components as isolated building blocks to reuse throughout an application. They accept inputs and return elements for updating the DOM.

Functional React components are pure. Just like pure functions in JavaScript their execution doesn’t depend on the state of the application, they don’t modify any variables outside their scope (no side effects!), and they always return the same result given the same arguments. Because of React’s adherence to pure components, learning React makes you a better developer. It also makes testing easier.

To start our avatar component, let’s think about what building blocks we’ll need to make it. An avatar has a user image, a user name and a probably a link to a user profile. Hmm, sounds like we need a user object. We’ll define one using an ES6 constant, call ReactDOM’s render method and pass it our forthcoming Avatar component.

const user_data = {
name: 'Chris Haaaaaaaack',
username: 'chryus',
image: 'https://avatars0.githubusercontent.com/u/5354390?v=3&s=460&#39;
}
ReactDOM.render(
<Avatar user={user_data} />,
document.getElementById('avatar')
)

view raw

user_data.js

hosted with ❤ by GitHub

ReactDOM’s render method takes two arguments — our avatar component that returns a UI object and the element in the DOM where the UI will be updated to. As we “invoke” the Avatar component we pass it the user as props, essentially parameters the component will use to create the UI. Now we can define an Avatar function and access the user object.

function Avatar(props) {
return (
<div>
<ProfilePic imageUrl={props.user.image} />
<ProfileName name={props.user.name} />
<ProfileLink username={props.user.username} />
</div>
);
}

view raw

avatar.js

hosted with ❤ by GitHub

Our Avatar component is comprised of three other components: ProfilePic, ProfileName and ProfileLink. Each needs access to some part of our user object. As we “invoke” the child components, we pass in the necessary props. It’s important to note that the React component rendered in the DOM must be wrapped in a div.

function ProfilePic(props) {
return (
<img src={props.imageUrl} style={{width:100, height:100}}/>
);
}
function ProfileName(props) {
return (
<div>{props.name}</div>
);
}
function ProfileLink(props) {
return (
<a href={'https://www.github.com/&#39; + props.username}>
{props.username}
</a>
);
}

With our child components we don’t need to worry about a container. Each child component can just return whatever element it needs to. And that’s pretty much all there is to building function react components. Nothing too fancy — it’s very similar to writing pure functions with JavaScript. The only difference is we’re returning JSX instead of primitive values.

Checkout the example on CodePen.

First React Component

In my last post, I showed how to set up the React environment — npm to download packages and their dependencies, webpack to minify and bundle code into one file for production, and Babel, a compiler that processes React into JavaScript the browser can understand.

I left off with using regular JavaScript to select an element and set its inner HTML to “Hello World!”. In this post we’ll use a React component to do that.

var app = document.getElementById('app');
app.innerHTML = "Hello World!"

view raw

index.js

hosted with ❤ by GitHub

Writing a React component is so much easier than setting up the React environment, because React is really just JavaScript. If you are comfortable with JS, it follows that you’ll be at ease with React.

In index.js, set two variables equal to the two React modules we downloaded in my last post, react and react-dom. The syntax for loading a module is require(insert-module-name).

var React = require('react');
var ReactDOM = require('react-dom');
var HelloWorld = React.createClass({
render: function () {
return (
<div>
<h1>Hello React!</h1>
</div>
)
}
});
ReactDOM.render(
<HelloWorld />,
document.getElementById("app")
);

view raw

index.js

hosted with ❤ by GitHub

On line 4, we’ll define our first React component and set it to a new variable, HelloWorld. We’ll start without using ES6, in which case you can use the createClass helper to initialize a component class. Every React component includes a render function that returns the HTML you want to display in the DOM.

On line 12, we use the render method from the the ReactDOM module to update the DOM with the output from our HelloWorld component/function. We pass it the component first, the selected element last.

Next run npm run start to start the development server, visit http://localhost:8080/ and you’ll see “Hello World!” displayed.

It’s always worth using a web inspector to see what’s being rendered in the DOM.

screen-shot-2016-12-29-at-10-53-04-am

As expected, the HelloWorld component has rendered inside the app. Note how the div element we rendered was automatically assigned a data-reactroot attribute. This allows tools like react-detector to identify a React app without any hiccups.

In my next post, I’ll demonstrate how functional components and props are used to organize your UI into reusable, isolated building blocks. All react components are pure; they always return the same result given the same arguments and never change the state of variables outside of their scope (no side effects!). This makes React components easy to test.

React Environment: NPM + Webpack + Babel

Building a React component is easy. It’s setting up the environment that’s tricky — you’ll need npm, webpack and Babel to get started. Once set up, webpack will take all your files, compile them into JavaScript the browser can understand, and output them to one single file.

To start a new React project, create a new directory call webpack-test-project and cd into it. Run npm init. This will create a package.json file in the root of your project.

Next run npm install –save react react-dom. This will create a new folder in the root of your project call npm_modules and will download the react and react-dom modules to it, along with any of their dependencies. As well, package.json will be populated with a dependencies object that includes any downloaded modules. This is great because instead of pushing all your modules to GitHub, a teammate can clone your project, run npm install, and presto, react and react-dom will be downloaded to their npm_modules folder.

{
"name": "webpack-test-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1"
}
}

view raw

package.json

hosted with ❤ by GitHub

Next, you need to install webpack via npm. webpack is module bundler. It will take our assets and transpile them according to the specifications in our config file. In this case, we’ll be configuring webpack to use babel and babel-preset-react to compile our code. By compile, I mean that webpack will process our React code to modern javascript that the browser can understand. Babel can also process ES6 & ES7 to JavaScript the browser can understand.

To install webpack and Babel run npm install –save-dev html-webpack-plugin webpack webpack-dev-server babel-{core,loader} babel-preset-react. Notice that this time we used –save-dev because we will only be using these packages in development mode. All of these packages will now be listed in package.json:

{
"name": "webpack-test-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-react": "^6.16.0",
"html-webpack-plugin": "^2.24.1",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
}
}

view raw

package.json

hosted with ❤ by GitHub

Next run mkdir app && cd app and create an index.js and index.html file. Then, in the root of the project create webpack.config.js — we’ll use this file to configure webpack.

module.exports = {
entry: [
'./app/index.js'
],
output: {
path: __dirname + '/dist',
filename: "index_bundle.js"
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"}
]
},
}

We configure webpack by building an exports object, with three important keys: entry, output, and module. Entry tells webpack which files to process; Output tells webpack to bundle your JS files into one new file called index_bundle.js that lives in a new folder /dist in the root of our project. Module tells webpack which loaders (processors) to use to compile our React code into JavaScript the browser can understand.

The Module object contains an array of loaders. In this case we only need one loader, babel-loader, to process our code. In the loaders array we tell webpack to take any file that ends in .js (except those in the node_modules folder) and process them with babel-loader.

But we aren’t finished yet, Babel has its on config file. Create a .babelrc file in the root of your project that tells Babel which presets/processors to run on your code, in this case react.

{
"presets": [
"react"
]
}

view raw

.babelrc

hosted with ❤ by GitHub

Ok, almost finished with configuration. The only outstanding issue is instruct webpack to create a new index.html file in the /dist folder and link to the bundled script, index_bundle.js. We will use the HTML webpack plugin to accomplish this task. Run npm install –save-dev html-webpack-plugin. This will update your dependencies in package.json and download the plugin to node_modules. Next, we initialize the plugin in webpack.config.js.

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
})
module.exports = {
entry: [
'./app/index.js'
],
output: {
path: __dirname + '/dist',
filename: "index_bundle.js"
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"}
]
},
plugins: [HtmlWebpackPluginConfig]
}

First, declare a new variable and set it to the HTML webpack plugin module. The object we pass to HtmlWebpackPlugin on initialization contains three properties: template, filename and inject. Template points to the file we would like to transform, filename specifies the name of our output, and inject specifies where in the output we want webpack to put the link to the bundled file, in this case the body tag. Then, at the end of the exports object, add a new property plugins and set it to our plugin instance, HtmlWebpackPluginConfig.

Phew, now all the architecture is in place but we still need to define scripts to run webpack. We’ll use two scripts, one for production, webpack -p, and one for development, webpack-dev-server, and put them in package.json. We’ve named our scripts production and start.

{
"name": "github-battle",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"production": "webpack -p",
"start": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-react": "^6.16.0",
"html-webpack-plugin": "^2.24.1",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
}
}

view raw

package.json

hosted with ❤ by GitHub

Scripts allow us to define shortcuts for common administrative tasks like bundling code. To bundle and compile our code for production as configured in webpack.config.js, run npm run production. After, you should have a new folder in your root project, /dist, with a new index.html file linking to a single compiled file, index_bundle.js, with all of our JavaScripts ready for the browser. You’re file structure should look like this after running the command.

screen-shot-2016-12-28-at-2-57-42-pm

Finally, let’s test this all out with some code. In index.html  create a div element with an id set to app.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Github Battle</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div id="app"></div>
</body>
</html>

view raw

index.html

hosted with ❤ by GitHub

And in index.js, fetch the app element and set its inner HTML to “Hello World!”.

var app = document.getElementById('app');
app.innerHTML = "Hello World!"

view raw

index.js

hosted with ❤ by GitHub

Run npm run production one more time. Now when you open ./dist/index.html you should see Hello World! in the top left of your window, which means npm, webpack and Babel are all working properly!

And check out your dist/index.html file. It should be exactly the same except it will link to index_bundle.js in the body.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Github Battle</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="index_bundle.js"></script></body>
</html>

view raw

index.html

hosted with ❤ by GitHub

index_bundle.js will contain a minified version of index.js, transpiled to browser-friendly JS.

!function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,r),o.loaded=!0,o.exports}var t={};return r.m=e,r.c=t,r.p="",r(0)}([function(e,r,t){e.exports=t(1)},function(e,r){var t=document.getElementById("app");t.innerHTML="Hello World!"}]);

view raw

index_bundle.js

hosted with ❤ by GitHub

Finally, because we aren’t in production mode most of the time, it makes more sense to only compile our code when pushing to production. While in development mode, take advantage of the start script we defined about in package.json. Run npm run start and you can view your progress at http://localhost:8080.

Setting up the environment for React is a bit complicated but it gets easier with practice. I recommend building the environment a few times. In my next post, I will show how to build a React component to display “Hello World!”.

For further information on setting up the React environment, check out this amazing free tutorial which informed much of this post.

 

 

 

 

Learning React: The Environment – NPM scripts

I’m excited to be learning a second front-end framework, React, because I like the idea of writing ES6 JavaScript components with embedded HTML instead of embedding HTML in JavaScript, like with Angular 1.

A prerequisite to learning React is having a basic understanding of its environment, which includes npm, the package manager for JavaScript. npm allows you to easily install and update modules like jQuery.

To initialize an npm project, run npm init from the console. This will generate a package.json file in the root folder of your project.

To install a package like jQuery, run npm install jquery –save. This creates a new folder called ‘node_modules’ in your project and downloads the jQuery package to it.

The –save part of the command will include jquery under dependencies in package.json. This is nifty because when a colleague clones your project, they can simply run npm install and any dependencies in package.json will be downloaded to their node_modules folder.

Another cool feature of npm is scripts. Scripts allow you to store commands that would otherwise be cumbersome to type out in the console. For example,  instead of always typing karma start –singleRun to run your Karma tests, you can define a script like…

{
"name": "first_react_component",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "karma start –singleRun",
},
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.1.1"
}
}

view raw

package.json

hosted with ❤ by GitHub

… and now you just have to type npm test to run your specs. This comes in handy as a project grows and files get deeply nested, as you deploy and have to manage ever more command line tasks.

When I first learned about npm scripts, I found it helpful to compare them with Rake tasks in Rails. Although Rake tasks are more substantive and involve functional code snippets, like npm scripts, they allow you to define administrative tasks and run them from the command line by their definition. Here’s a fallback Rake task I wrote to upload files to Amazon S3 that are older than 300 seconds:

require './app/services/fog_service'
require 'task_helpers/clean_up_helper'
task :upload_jobs do
Dir.glob("tmp/uploads/*/*.*") do |file|
age = CleanUpHelper.file_age(file)
if age > 300
fog = FogService.create
destination = fog.directories.get('default-submissions-uploads')
destination.files.create(key: file.split("/").last, body: File.read(file))
end
end
end

To execute this task you would run rake:upload_jobs from Rails console, or use a scheduler to automate it every few hours.

Next I’ll be learning about the module bundler webpack and building my first React component!

 

Hooray for ES6 modules on Rails Part 2: Testing

In my last post, I integrated modern JS into a Rails app with Browserify via Browserify-Rails gem, and getting started with writing specs in ES6 is just as easy.

1.) Set up Browserify-Rails via my last post

2.) Add teaspoon-jasmine gem to your gemfile

gem "browserify-rails"
group :development, :test do
# Your choice of test library.
# Also available, teaspoon-mocha / teaspoon-qunit
gem "teaspoon-jasmine"
# Teaspoon's front-end is written in CoffeeScript but it's not a dependency
gem "coffee-script"
end

view raw

gemfile.rb

hosted with ❤ by GitHub

3.) Make sure Browserify is configured to load spec files

unless Rails.env.production?
# Make sure Browserify is triggered when asked to serve javascript spec files
config.browserify_rails.paths << lambda { |p|
p.start_with?(Rails.root.join("spec/javascripts").to_s)
}
end

view raw

_application.rb

hosted with ❤ by GitHub

4.) Run “bundle install” from Rails console

5.) Run “bundle exec rails g teaspoon:install” from Rails console

6.) Import whatever class you are testing and use ES6 syntax!

import Cell from "../../app/assets/javascripts/Cell.es6";
describe("Cell", function() {
var cell;
beforeEach(() => {
cell = new Cell(false, 1, 1);
});
it("should respond properly to methods", () => {
expect(cell.alive).toBe(false);
expect(cell.x).toBe(1);
expect(cell.y).toBe(1);
});
});

view raw

cell_spec.js

hosted with ❤ by GitHub

7.) Run your specs in the browser at http://localhost:3000/teaspoon, or in the console via rake teaspoon

screen-shot-2016-12-23-at-2-15-08-pm

gem "browserify-rails"
group :development, :test do
# Your choice of test library.
# Also available, teaspoon-mocha / teaspoon-qunit
gem "teaspoon-jasmine"
# Teaspoon's front-end is written in CoffeeScript but it's not a dependency
gem "coffee-script"
end

view raw

gemfile.rb

hosted with ❤ by GitHub

Hooray for ES6 modules on Rails Part 1: Getting Started

In my most recent project, I implemented Conway’s Game of Life using ES6 modules + Rails. With the help of Browserify via Browserify Rails, I was able to organize my code with node-flavored modules and compile them with Babelify for use in the browser.

It’s the first app I’ve built using modern javascript, and doing so was rewarding and a good primer for using ES6 with front-end frameworks like React moving forward (I did not use a front-end framework in this project).

Getting started with Browserify via Browserify Rails is super easy. If you don’t already have node installed, you can do so via Homebrew. Once node is installed, follow these directions to get up and running with ES6:

1.) Add “gem browserify-rails” to your gemfile

2.) Run “bundle install” from Rails console

3.) In application.rb, config Browserify to use Babelify to compile ES6

# config/application.rb
# Configure Browserify to use babelify to compile ES6
config.browserify_rails.commandline_options = "-t [ babelify –presets [ es2015 ] ]"
# Run on all javascript files
config.browserify_rails.force = true
# Alternatively, only run on .es6 files
# config.browserify_rails.force = ->(file) { File.extname(file) == ".es6" }
unless Rails.env.production?
# Make sure Browserify is triggered when asked to serve javascript spec files
config.browserify_rails.paths << lambda { |p|
p.start_with?(Rails.root.join("spec/javascripts").to_s)
}
end

view raw

application.rb

hosted with ❤ by GitHub

3.) Run “npm init” from Rails console to create a package.json file in Rails root. Add the following dependencies:

{
"name": "something",
"dependencies" : {
"browserify": "~10.2.4",
"browserify-incremental": "^3.0.1"
},
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
}

view raw

package.json

hosted with ❤ by GitHub

4.) Run “npm install browserify browserifyincremental babelify babelpresetes2015 save” from Rails console to install the required packages locally

5.) Start writing ES6 classes and export them for use in other classes (via import).

Example of exported Cell class:

class Cell {
constructor(alive, x, y) {
this.alive = alive;
this.x = x;
this.y = y;
}
die () { this.alive = false; }
revive () { this.alive = true; }
isAlive () { return this.alive; }
dead () { return !this.alive; }
}
export default Cell;

view raw

Cell.es6

hosted with ❤ by GitHub

Example of importing Cell class and using its initialize method in World class:

// import Cell class
import Cell from './Cell.es6';
class World {
constructor (cols, rows) {
this.cols = cols;
this.rows = rows;
this.cellGrid = [];
this.makeGrid();
}
makeGrid () {
let i = 0;
while (i < this.rows) {
let rowArray = [];
let j = 0;
while (j < this.cols) {
let cell = new Cell(false, j, i); // use Cell class initialize method
this.cells.push(cell);
rowArray.push(cell);
j++;
}
this.cellGrid.push(rowArray);
i++
}
}
}
export default World;

view raw

world.es6

hosted with ❤ by GitHub

6.) Require all classes/modules in application.js

// require node-flavored modules in the manifest
//= require jquery
//= require tether
//= require bootstrap-sprockets
//= require bootstrap-slider
//= require jquery_ujs
//= require turbolinks
//= require_tree .
require("./Cell.es6");
require("./World.es6");
require("./Game.es6");

view raw

application.js

hosted with ❤ by GitHub

That’s it. You’re now ready to use modern JS in the browser and feel confident that you are current with the ever-changing JavaScript landscape.

Postscript: If you haven’t built Conway’s Game of Life before, I highly recommend getting started with this fantastic test-driven tutorial. And definitely solve the problems on your own when he gives you a challenge; you will learn a ton more that way and feel good about it. Note that this is a ruby tutorial and the game is displayed via the Gosu gem in the console. The ES6 stuff above is only applicable if you build the game in the browser.