What the
Flux is
React
James Bjorkman
Facebook had a problem
Many People + Many Features + MVC
=
Really Bad Time
With each new feature
- Predictability of codebase decreases.
- Complexity of entire system grew more quickly.
- Code was responsible for doing more things.
- Data was used in more places.
- Harder to bring new engineers up to speed.
- System becomes harder to debug.
- Harder to make changes confidently.
- Harder to maintain and optimize.
- Features take longer to build.
- Code moves slower because it becomes more
- and more fragile.
Hypothesis
By structuring code in a way
that makes it more predictable
higher quality applications
can be shipped in less time,
new engineers can be
brought up to speed quicker,
everyone can make
changes more confidently.
Flux
Predictable Single Direction Data Flow
React
Declarative, Predictable, User Interfaces
Flux
Action -> Dispatcher -> Stores -> View
- User does Action
- Action builds payload & sends to Dispatcher
- Dispatcher gives payload to the registered Stores
- Store takes payload and deals with it.
- When a store changes, views rerender.
// View (Trigger Action)
ItemActions.newItem('Bob');
// Action (Build Payload)
ItemActions = {
newItem: function (title) {
AppDispatcher.handleViewAction({
actionType : ItemConstants.ITEM_CREATE,
title : title
});
}
};
// Store (Deal with payload)
AppDispatcher.register(function (payload) {
var action = payload.action;
switch (action.actionType) {
case ItemConstants.ITEM_CREATE:
createItem(action.title); // Function handles ajax and all that
break;
}
ItemStore.emitChange(); // Tell views to re-render
return true; // Used for the Dispatcher Promises
});
REACT
- Single Direction
- Virtual Dom
- Synthetic Events
- Small Single Purpose Components
- Easily Testable
- Optimised Batch Updates of DOM
- Push complexity of DOM mutations into framework
- JSX
- Virtual DOM representations can be rendered
on the server and sent as the response.
- Passed Properties From Above
A SIMPLE Component
var React = require('react');
var HelloWorld = React.createClass({
render: function () {
return React.DOM.div({className: "HelloWorld"}, "Hello World");
}
});
React.renderComponent(
HelloWorld(),
document.body
);
A Slightly More complex COMPONENT
var Counter = React.createClass({
getInitialState: function () { return {count: 0} },
render: function () {
return React.DOM.div({className: "Coutner"}, [
React.DOM.div({}, [
this.state.count,
React.DOM.button( {onClick: this.inc}, '+1' )
])
]);
},
inc: function () {
this.setState({count: this.state.count + 1});
}
});
JSX
/** @jsx React.DOM */
var Counter = React.createClass({
getInitialState: function () { return {count: 0} },
render: function () {
return (
<div className="Counter">
{this.state.count}
<button onClick={ this.inc }>+1</button>
</div>
);
},
inc: function () {
this.setState({count: this.state.count + 1});
}
});
Components in Components
/** @jsx React.DOM */
var Counters = React.CreateClass({
render: function () {
return (
<div>
<h1>Counters</h1>
<Counter />
<Counter />
<Counter />
<Counter />
<Counter />
</div>
);
}
});
With Flux
var CounterStore = require('./store/CounterStore');
var CounterActions = require('./actions/CounterActions');
function getState () { /* returns state from CounterStore */ }
var Counter = React.CreateClass({
getInitialState: function () { return getState(); },
componentWillMount: function () {
CounterStore.on('CHANGE', this.updateState);
},
componentWillUnmount: function () {
CounterStore.off('CHANGE', this.updateState);
},
updateState: function () { this.setState(getState()); },
inc: function () { CounterActions.inc(this.state.id); },
render: function () { /* Same as Before */ }
})