"The faster you react, the less you think."
- Jason Fried
https://signalvnoise.com/posts/3124-give-it-five-minutes
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
// Initialize stuff on load
$(document).ready(function() {
initializeABunchOfThings();
});
// Scattered Events Everywhere
$('#button-1').on('click', function() {
$(this).toggle('active')
});
$('#button-2').on('click', function() {
if ($('#button-1').hasClass('active') {
doSomething();
} else {
doAnotherThing();
}
});
Front End, Stampsy
ids = [1, 2, 3, 4, 5]
ids.remove(1)
# => [2, 3, 4, 5]
ids.remove(1)
# => [2, 3, 4, 5]
DATA
IN
VIRTUAL DOM
OUT
/** @jsx React.DOM */
var HelloMessage = React.createClass({
displayName: 'HelloMessage',
render: function() {
return (
React.DOM.div(null, "Hello ", this.props.name)
);
}
});
React.renderComponent(HelloMessage({
name: "John"
}), document.getElementById('content'));
2. CHILD ELEMENTS
1. NODE PROPERIES
{ id: 'name' }
3. PROPS
4. COMPONENT
HelloMessage Component
/** @jsx React.DOM */
var HelloMessage = React.createClass({
render: function() {
return (
<div>
Hello {this.props.name}
</div>
);
}
});
React.renderComponent(<HelloMessage name="John" />, mountNode);
HelloMessage Component (JSX)
<div id="content">
<div data-reactid=".0">
<span data-reactid=".0.0">Hello </span>
<span data-reactid=".0.1">John</span>
</div>
</div>
HTML OUTPUT
/** @jsx React.DOM */
var Timer = React.createClass({
getInitialState: function() {
return {
secondsElapsed: 0
};
},
tick: function() {
this.setState({
secondsElapsed: this.state.secondsElapsed + 1
});
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function() {
return (
<div>
Seconds Elapsed: {this.state.secondsElapsed}
</div>
);
}
});
React.renderComponent(<Timer />, mountNode);
Timer Component
getInitialState: function() {
return {
secondsElapsed: 0
};
},
SET THE INITIAL STATE
ON COMPONENT MOUNT
// this.tick();
tick: function() {
this.setState({
secondsElapsed: this.state.secondsElapsed + 1
});
},
DEFINE A FUNCTION
UPDATE THE STATE
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
SET THE TIMER
PASSING THE TICK FUNCTION
ON MOUNT
componentWillUnmount: function() {
clearInterval(this.interval);
},
REMOVE THE TIMER BEFORE
COMPONENT IS UNMOUNTED
render: function() {
return (
<div>
Seconds Elapsed: {this.state.secondsElapsed}
</div>
);
}
DEFINE THE MARKUP IN RENDER
// JSX
React.renderComponent(<Timer />, mountNode);
// JS
React.renderComponent(Timer(null), mountNode);
RENDER THE COMPONENT
/** @jsx React.DOM */
// props:
// currentLat, count, modules
var LiModules = React.createClass({
render: function() {
var moduleNodes = this.props.modules.map(function(module, index) {
return (
<LiModule
id={module.id}
name={module.name}
activities={module.activities}
currentLat={this.props.currentLat}
polling={this.props.polling}
key={index}
/>
);
}.bind(this));
return (
<div className="launchpad-module-groups">
<div className="box instance-group">
<LiModulesHeader count={this.props.count} />
<div className="box-content scrollable instances launchpad-modules">
{moduleNodes}
</div>
</div>
</div>
);
}
});
NESTING
PROPS
UNIDIRECTIONAL FLOW
O(n^3) problem into a O(n) one.
var BottleGame = React.createClass({
getInitialState: function () {
return {
bottles: 99
};
},
render: function() {
var bottles = this.state.bottles,
warning = (this.state.bottles < 10 ? 'warning' : false);
return (
<div>
<p className={warning}>Bottles: {text}</p>
{bottles > 0 ?
<button onClick={this.handleTakeClick}>Take one down and pass it around</button> :
<button onClick={this.handleAgainClick}>Start again</button>
}
</div>
);
},
handleTakeClick: function () {
this.setState({ bottles: this.state.bottles - 1 });
},
handleAgainClick: function () {
this.setState({ bottles: 99 });
}
});
React.renderComponent(BottleGame(), document.body);
BottleGame
React Component
getInitialState: function () {
return {
bottles: 99
};
},
INITIALIZE STATE
handleTakeClick: function () {
this.setState({ bottles: this.state.bottles - 1 });
},
handleAgainClick: function () {
this.setState({ bottles: 99 });
}
DEFINE HANDLERS
TO UPDATE STATE
render: function() {
var bottles = this.state.bottles,
warning = (this.state.bottles < 10 ? 'warning' : false);
return (
<div>
<p className={warning}>Bottles: {text}</p>
{bottles > 0 ?
<button onClick={this.handleTakeClick}>
Take one down and pass it around
</button> :
<button onClick={this.handleAgainClick}>
Start again
</button>
}
</div>
);
},
RENDER MARKUP
var para = $('#bottles'),
take = $('#take'),
again = $('#again'),
bottles = 99;
function update() {
if (bottles > 0) {
take.show();
again.hide();
} else {
take.hide();
again.show();
}
if (bottles > 1) {
para.text(bottles + ' bottles of beer on the wall');
} else if (bottles === 1) {
para.text('One bottle of beer on the wall');
} else {
para.text('No bottles of beer on the wall');
}
}
take.click(function () {
bottles--;
update();
});
again.click(function () {
bottles = 99;
update()
});
update();
<p id="bottles">9 bottles...</p>
<button id="take">Take one...</button>
<button id="again">Start...</button>
BottleGame jQuery
var BottleGameView = Backbone.View.extend({
el: '#container',
events: {
'click button.take': 'takeBottle',
'click button.again': 'startAgain'
},
initialize: function () {
this.model = new Backbone.Model({ bottles: 99 });
this.render();
this.listenTo(this.model, 'change:bottles', this.handleBottlesChange);
},
handleBottlesChange: function () {
var bottles = this.model.get('bottles');
if (bottles > 0) {
this.$take.show();
this.$again.hide();
} else {
this.$take.hide();
this.$again.show();
}
if (bottles > 1) {
this.$para.text(bottles + ' bottles of beer on the wall');
} else if (bottles === 1) {
this.$para.text('One bottle of beer on the wall');
} else {
this.$para.text('No bottles of beer on the wall');
}
},
render: function () {
var template = _.template($('#bottles_template').html(), this.model.attributes);
this.$el.html(template);
this.$para = this.$el.find('.bottles');
this.$take = this.$el.find('.take');
this.$again = this.$el.find('.again');
this.$again.hide();
},
takeBottle: function () {
this.model.set('bottles', this.model.get('bottles') - 1);
},
startAgain: function () {
this.model.set('bottles', 99);
}
});
new BottleGameView();
BottleGame Backbone
var BottleGame = React.createClass({
getInitialState: function () {
return {
bottles: 99
};
},
render: function() {
var bottles = this.state.bottles,
warning = (this.state.bottles < 10 ? 'warning' : false);
return (
<div>
<p className={warning}>Bottles: {text}</p>
{bottles > 0 ?
<button onClick={this.handleTakeClick}>Take one down and pass it around</button> :
<button onClick={this.handleAgainClick}>Start again</button>
}
</div>
);
},
handleTakeClick: function () {
this.setState({ bottles: this.state.bottles - 1 });
},
handleAgainClick: function () {
this.setState({ bottles: 99 });
}
});
React.renderComponent(BottleGame(), document.body);
BottleGame React Component
BACKBONE
NESTED COMPONENTS
REACT COMPONENTS