Intro to React – Featuring Modern JavaScript – React



Intro to React – Featuring Modern JavaScript – React

0 0


grdevday-react-slides

Slides for GR DevDay talk "Intro To React - Featuring Modern JavaScript"

On Github brianium / grdevday-react-slides

Intro to React

Featuring Modern JavaScript

By Brian Scaturro / @scaturr & Jason Sich / @jasich

React

A JavaScript library for building user interfaces

http://facebook.github.io/react/

And to steal bullet point's from React's website:

JUST THE UI

Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project.

Virtual Dom

React uses a virtual DOM diff implementation for ultra-high performance. It can also render on the server using Node.js — no heavy browser DOM required.

Data Flow

React implements one-way reactive data flow which reduces boilerplate and is easier to reason about than traditional data binding.

Components FTW

It's about separation of (application) concerns.

Thinking in components

Components as state machines

Components have various states, and we render different views for different states.

Components are composable

                            
render() {
    return <div>
             <MealList meals={this.state.meals} />
             <ChoiceFilter />
             <ChoiceList allChoices={this.state.allChoices} / >
           </div>
}
                            
                        

State can live at the top and be passed down via properties.

Styling Components

So like....I've heard React is all about inline styles. Whhuuuutttt?

Well.....yes and no

Styles are really just state too.

                            
const dropState = this.getDropState('choice');
let styles = {};

if (dropState.isHovering) { //yup that's state
    styles.backgroundColor = '#FFD34E';
}

if (this.props.selection) { //yeah that's state too
    styles.backgroundImage = 'url(' + this.props.selection.picUrl + ')';
}
                            
                        

The end result is that styles benefit from reactive goodness. State change = style change.

And it's still HTML

At the end of the day, the end result is an HTML document. HTML documents can have links to stylesheets.

Using ES6 in React

Introducing React with idiomatic ES6.

React v0.13.0 allows for implementing components using JavaScript classes

JSX transformers allow for transpiling of ES6 to ES5 code

Classes and modules example

                            
import React from 'react';

class ChoiceRow extends React.Component {

}

export default ChoiceRow;
                            
                        

ES6 in action

                            
// `let` keyword
let choices = this.props.choices;

// arrow and map function
let children = choices.map(c => (<Choice item={c} />));

return <div className="row">
         {children}
       </div>
                            
                        

proxies, promises, let, const, generators, etc...

Bottomline, the next evolution of JavaScript gives us a lot of cool stuff, and it would be really nice to use today.

Unfortunately...

ES6 is not very well supported in most browsers.

There is hope!

A lot of really smart people are working towards making ES6 usable today.

Perceived

(and maybe some actual)

Downsides

Synthetic events

Inline styles

Too much rendering?

Lots of code

Building React Applications With Flux

Immutability! Unidirectional data flow!

The dispatcher, stores and views are independent nodes with distinct inputs and outputs. The actions are simple objects containing the new data.

https://facebook.github.io/flux/docs/overview.html#content

MVC doesn't scale

Views create new actions

Perhaps with a search form?

                            
class ChoiceFilter extends React.Component {
  render() {
    return <input type="text" onChange={this._onChange} />
  }

  _onChange(event) {
    ChoiceActions.filter(event.target.value); //create an action!
  }
}
                            
                        

ChoiceActions.js

Stores respond to actions

Stores respond to actions, and emit change events.

                            
const store = new ChoiceStore();
AppDispatcher.register(function (action) {
  switch(action.actionType) {
    case ChoiceConstants.CHOICE_FILTER:
      store.filter(action.search);
      store.emit(CHANGE_EVENT); //there is a change!
      break;
    default:
      break;
  }
});
export default store; //yup that's a single store
                            
                        

Views ASK for data

In a departure from the prevalent "two-way binding" sorcery, views listen for changes and ask for data.

An example

                            
let getState = () => {
  allChoices: ChoiceStore.getChoices() //asking for data
}

class MealPlanner extends React.Component {
  constructor() {
    this.state = getState(); //initial state
  }

  componentWillMount() {
    ChoiceStore.addChangeListener(this._onChange.bind(this)); //listen
  }

  _onChange() {
    this.setState(getState()); //there was a change - ask for data
  }

  render() {
    // render the component
  }
}
                            
                        

But why?!?!?!

We found that two-way data bindings led to cascading updates, where changing one object led to another object changing, which could also trigger more updates. As applications grew, these cascading updates made it very difficult to predict what would change as the result of one user interaction. When updates can only change data within a single round, the system as a whole becomes more predictable.

https://facebook.github.io/flux/docs/overview.html#content

The Tools

Currently we have to jump through hoops to transpile ES6 to ES5, and use handy things like JSX.

It's nice necessary to have tools to do it for us

What we want out of a workflow

Transpile ES6 to ES5 Compile JSX to JavaScript Launch or reload a browser Compile SCSS, Jade, whatever Do this all when we change a file

The less we have to focus on building and running, the better

There are a lot of tools out there, here are a few we find useful

Testing With Jest

Hey! It's worth a mention.

Oh... another Jasmine style testing framework?

The Angular team built karma The React team built Jest OK

So... this one does what?

  • Mock by default
  • Fake DOM via jsdom

Some new things, it's cool (but so is anything that lets you test your code)

In the land of React

                            
jest.dontMock('../ChoiceStore');
jest.dontMock('../../data.json');

describe('ChoiceStore', function () {
  let ChoiceStore;
  let data;

  beforeEach(function () {
    ChoiceStore = require('../ChoiceStore');
    data = require('../../data.json');
  });

  describe('.getChoices()', function () {
    it('should return all meal options by default', function () {
      let choices = ChoiceStore.getChoices();
      expect(choices.length).toEqual(data.mealOptions.length);
    });
  });
});
                            
                        

A note on ES6 in tests

It requires the babel-jest package (or a similar transpile hook), and a little tweak to your package.json file.

                            
"jest": {
  "scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
  "testFileExtensions": [
    "js"
  ],
  "moduleFileExtensions": [
    "js"
  ]
}
                            
                        

Mixins

React doesn't really go for subclassing components, but it does provide support for the timeless JavaScript classic, the mixin.

Quick review

A mixin is an object that typically gets merged into the prototype of another object - effectively adding that behavior to instances of the target object.

Add hover functionality?

                            
let HoverMixin = {
  componentWillMount() {
    this.state = this.state || {};
    this.state.hovered = false;
  },
  componentDidMount() {
    this.getDomNode().addEventListener('mouseover', this._onMouseOver.bind(this));
    this.getDomNode().addEventListener('mouseout', this._onMouseOut.bind(this));
  },
  componentWillUnmount() {
    this.getDomNode().removeEventListener('mouseover', this._onMouseOver.bind(this));
    this.getDomNode().removeEventListener('mouseout', this._onMouseOut.bind(this));
  },
  _onMouseOver() {
    this.setState({hovered: true});
  },
  _onMouseOut() {
    this.setState({hovered: false});
  }
}

export default HoverMixin;
                            
                        

The component* life cycle events can be duplicated. React allows multiple definitions for those when creating mixins.

Do the mixing

                            
import HoverMixin from 'HoverMixin';
import React from 'react';

const MyComponent = React.createClass({
   mixins: [HoverMixin]
});

export default MyComponent;
                            
                        

The struggle of mixins

Note the React.createClass call. Unfortunately ES6 does not have an official mixin mechanism, so we have to use this means of creating a component.

React On The Server And Client

Isomorphic JavaScript applications can run on both the server and client. React has a node module which allows it to be rendered on the server.

Future React

https://github.com/reactjs/react-future

Examples

A React app using webpack and friendshttps://github.com/jasich/meal-planner

A React app using browserify and friendshttps://github.com/brianium/plan-and-eat