Shindig: React.js + Coffeescript

Chet Corcos
3 min readNov 24, 2015

--

Perhaps my favorite thing about React is that I’m not longer constrained to markup languages like HTML, Handlebars, Angular, or Blaze. Finally I have turing complete language to build my entire user interface! But for some reason, Facebook decided it was a little too radical to be coding your entire UI in Javascript and wanted to give developers a taste of the web’s humble beginnings. So they created a transpiled language called JSX to embed HTML in Javascript. Most people seem to love it, but I’m not the biggest fan.

A lot of people hate on Coffeescript and I don’t really know why. Nor do I really care. I love Coffeescript! And major kudos for Jeremy’s Terminator-themed talk. Anyways, when you’re getting started with React without using JSX, there’s a few things that aren’t explained very well in the documentation.

React components are just functions. Their first argument is an object describing the props and the rest of the arguments are just its children.

{div} = React.DOM
div({className: 'app'}, 'Hello World!')

The JSX equivalent is:

<div className="app">Hello World</div>

The other thing that is a little tricky is when you create a component with React.createClass, you’ll need to wrap it in React.createFactory in order to use it as a function. For backward-compatibility, you don’t have to do this with any of the React.DOM components but you do with your own.

createView = (spec) ->
React.createFactory(React.createClass(spec))
App = createView
render: ->
div({className: 'app'}, "Hello #{@props.name}!")
React.render(App({
name: "Del The Funky Homosapien"
}), document.body)

Coffeescript has a relatively loose syntax so you’re given a lot of freedom in how you stylistically write your code. At first, I used a more Lispy style with tons of parens:

(div {className: 'app'},
'Hello World!'
)

This was fine and I used it for a while until I played around on js2.coffee and discovered the ultimate coffeescript way of writing React.

div
className: 'app'
'Hello World!'

Boom! No more compile errors due to missing parens, braces, or commas. This works because coffeescript lets you return before specifying arguments to a function only when the first argument is an object. And once that object is done, it treats the rest of the returns as argument separators. Now the DOM structure is very clear and based on indentation (better turn your tab guides on in your text editor).

I also found it very useful to define a simple if-else function so that logic can be baked right into the DOM structure.

cond = (a,b,c) -> if a then b() else c?()

Here’s a simple example using it:

render: ->
Transition
transitionName: 'fade'
cond @props.loading,
=>
Loading
key:'loading'
=>
div
key: 'view'
className: 'event view'
img
className: 'cover'
src: @props.event?.cover?.source
div
className: 'title row pointer'
a
href: facebookLink(@props.event.id)
@props.event.name

React.js + Coffeescript + Meteor

To get started, you first need to add a couple packages to your Meteor project.

meteor add react-runtime
meteor add coffeescript

If you’re going to using this React app on mobile, then there are a few quirks to be aware of.

  1. If you want touch events to work, then you need to initialize them (React ≤ 0.13).
React.initializeTouchEvents(true)

2. If you want touch events to trigger onClick events, then any element you want to be touch-clickable needs to have a cursor: pointer CSS style. I just create a CSS class for this.

.pointer {
cursor: pointer;
}

3. If you want the :active CSS pseudoselector to work for touch events, then you need to add an event listener to the document. This selector is helpful for styling buttons while they’re being held down.

document.addEventListener(“touchstart”, (()->), false)

I usually put this stuff in a client/lib/init.coffee file, and because you’re probably going to be using them a bunch, I like to define some global variables as well.

{@div, @span, @input, @img, @button} = React.DOM
@Transition = React.createFactory(React.addons.CSSTransitionGroup)
@cond = (a,b,c) -> if a then b() else c?()
@createView = (spec) ->
React.createFactory(React.createClass(spec))

So now you’re up and running with Coffeescript and React. Now its time to build some cool stuff!

--

--