On Github brianium / grdevday-react-slides
By Brian Scaturro / @scaturr & Jason Sich / @jasich
A JavaScript library for building user interfaces
http://facebook.github.io/react/
And to steal bullet point's from React's website:
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.
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.
React implements one-way reactive data flow which reduces boilerplate and is easier to reason about than traditional data binding.
It's about separation of (application) concerns.
Components have various states, and we render different views for different states.
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.
So like....I've heard React is all about inline styles. Whhuuuutttt?
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.
At the end of the day, the end result is an HTML document. HTML documents can have links to stylesheets.
React v0.13.0 allows for implementing components using JavaScript classes
JSX transformers allow for transpiling of ES6 to ES5 code
import React from 'react'; class ChoiceRow extends React.Component { } export default ChoiceRow;
// `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>
Bottomline, the next evolution of JavaScript gives us a lot of cool stuff, and it would be really nice to use today.
ES6 is not very well supported in most browsers.
A lot of really smart people are working towards making ES6 usable today.
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.
class ChoiceFilter extends React.Component { render() { return <input type="text" onChange={this._onChange} /> } _onChange(event) { ChoiceActions.filter(event.target.value); //create an action! } }
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
In a departure from the prevalent "two-way binding" sorcery, views listen for changes and ask for data.
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 } }
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.
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
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
Hey! It's worth a mention.
The Angular team built karma The React team built Jest OK
Some new things, it's cool (but so is anything that lets you test your code)
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); }); }); });
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" ] }
React doesn't really go for subclassing components, but it does provide support for the timeless JavaScript classic, the mixin.
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.
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.
import HoverMixin from 'HoverMixin'; import React from 'react'; const MyComponent = React.createClass({ mixins: [HoverMixin] }); export default MyComponent;
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.
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.
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