React Primer

An intro to using react.js for those new to react, but comfortable with MVC frontend code.

UI

React is really two things: a way to abstract DOM creation and a way of building UI that removes a lot of boilerplate.

Creating components

React can feel very old school sometimes, in a good way—First get server-side rendering working, much later add client JS as an optimization via https://twitter.com/markdalgleish/status/580098832043655168

Because we have abstracted DOM creation, we have the server render out our HTML and then have JS take over when it's ready. This gives us:

  1. Much faster initial load. Delivering HTML from the server is a lot faster than having to download a massive JS bundle first, parse it, download related data, parse that, then output DOM.
  2. Progressive enhancement. This means we can work better in environments that do not support all the JS features we'd like, or have user interaction before the JS is done working. for this reason, it's critical that you use HTML as it's intended and deal with states that JS would normally handle. For example, it's important that we use <form> elements and actually give them an action attribute so they can submit data without the JS. Get <button> and <a> tags right. <a href="#"> is an anti-pattern. The client needs to have a router that matches what the server routes and it's important that the router works! [video intro to React Router]
  3. Of course, server-side rendering also means we get accessibility. Google can now index us!

Lots of boilerplate can be removed, because React as a very succinct lifecycle.

React lifecycle

Tutorials

React has some new terminology but it's pretty easy to understand. Here are 7 quick demos for making components. There are some best practices. I'd add that using this.state in a component is generally agreed to be a bad idea™. Pass in what you need with this.props, and store state in a global, immutable, object.

Here's a look at a sample app with flux and react for managing GitHub Issues.

Composition vs. Inheritance vs. Mixins

React keeps our practice of making components that do not fetch data and components that do. Think of it as smart vs dumb components

Keep in mind, inheritance and mixins are frowned on. Use composition for this purpose.

// via https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775
// enhance.js
import { Component } from "React";

export var Enhance = ComposedComponent => class extends Component {
  constructor() {
    this.state = { data: null }
  }
  componentDidMount() {
    this.setState({ data: 'Hello' })
  }
  render() {
    return <composedcomponent {...this.props}="" data="{this.state.data}">
  }
}

// HigherOrderComponent.js
import { Enhance } from "./Enhance"

class MyComponent {
  render() {
    if (!this.data) return Waiting...
    return {this.data}
  }
}

export default Enhance(MyComponent) // Enhanced component

Data

Even though React is just a view layer, it has a good answer for how to get data into the views with flux. Think of flux as a pattern not a library. You use flux instead of MVC, just as you might use socket.io in place of REST.

Flux for stupid people is a great intro. As is What the Flux.

I prefer flummox with immstruct.

import { Actions, Store, Flummox } from 'flummox'
import immstruct from 'immstruct'
import Immutable from 'immutable'

export class UserActions extends Actions {
  setEmail (content) {
    if (!content.email.includes('@')) throw new Error('must have valid email')
    return content // automatically dispatched
  }
}

export class UserStore extends Store {

 constructor (flux) {
    super()

    const userActions = flux.getActions('users')
    this.register(userActions.setEmail, this.setEmail)

    // a reference is like a cursor, but it always points to the freshest data
    this.state = flux.state.reference(['users'])
    // we're bypassing the setState method with immutable data, so trigger an update manually
    this.observer = this.state.observe(this.forceUpdate.bind(this))
  }

  setEmail (content) {
    this.state.cursor([content.id]).set('email', content.email)
  }

  // useful so that react views don't need to deal with immutable data
  get (id) {
    return this.state.cursor(id).toJSON()
  }

  // example of how to merge data
  set (id, attr, value) {
    if (typeof attr === 'string') this.state.cursor([id, attr]).update(() => value)
    else {
      this.state.cursor([id.id]).update((current) => current.mergeDeep(id))
    }
  }

}

export class Flux extends Flummox {

 constructor (initialData) {
    super()

    this.state = immstruct.withHistory('stores', initialData)
    this.createActions('users', UserActions)
    this.createStore('users', UserStore, this)
  }

}

No more MVC

The unidirectional data flow is [video] makes the idea of controllers obsolete. Stores are kinda like collections, but should be simpler – mostly because we should use immutable data. Flux actions and dispatchers replace the what models/collections do in a backbone app for fetching data. Talking to the server is not something that Flux builds in, but it's easy to reason out. Flux solves many problems that are common with client-side MVC. It simplifies dealing with:

  • data that changes with time
  • data that is cached locally, but can be changed by the server
  • data that is relational
  • data that has to be shown in multiple places in the UI

Immutability

Immutable data is a huge win for simplifying data access and storage. Combined with the fact that re-rendering the whole app in React is a very cheap operation, immutability means that we don't have to attach change listeners all over the place. We just have one change listener attached to the global immutable object and re-render the whole app on any change.

Here's a good intro to React and Immutability [video]

Isomorphism

Here's how Yahoo solved the problem of getting data to React views on both the server and the client. Really, the whole problem is easy with flux implementation like flummox and react-router.

import Router from 'react-router'
import React from 'react'
import routes from './react-router-routes.jsx'

function serveHTML (req, res) {
  ReactRouter.run(routes, req.url, (Handler) => React.renderToString(React.createElement(Handler, data)))
}

Relay and the Future

Relay isn't open source yet, but it's a really exciting and new way of fetching data from views. Here's a first look at what Relay will do, and here's an updated walk through.

React-awesome

A massive list of anything I might have missed