Skip to content

Instantly share code, notes, and snippets.

@colinyoung
Created July 9, 2015 16:43
Show Gist options
  • Save colinyoung/0c0bfea10431d56682c7 to your computer and use it in GitHub Desktop.
Save colinyoung/0c0bfea10431d56682c7 to your computer and use it in GitHub Desktop.
React talk
<!DOCTYPE html>
<html>
<head>
<title>Foo</title>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' />
<style type='text/css'>
div {
cursor:pointer;
cursor:hand;
position:absolute;
top:0;
left:0;
}
</style>
<script type='text/javascript'>
window.onload = function() {
var s = document.getElementsByTagName('div'), cur = 0, ti;
if (!s) return;
function go(n) {
cur = n;
var i = 1e3, e = s[n], t;
document.body.className = e.dataset.bodyclass || '';
for (var k = 0; k < s.length; k++) s[k].style.display = 'none';
e.style.display = 'inline';
e.style.fontSize = i + 'px';
if (e.firstChild && e.firstChild.nodeName === 'IMG') {
document.body.style.backgroundImage = 'url(' + e.firstChild.src + ')';
e.firstChild.style.display = 'none';
if ('classList' in e) e.classList.add('imageText');
} else {
document.body.style.backgroundImage = '';
document.body.style.backgroundColor = e.style.backgroundColor;
}
if (ti !== undefined) window.clearInterval(ti);
t = parseInt(e.dataset.timeToNext || 0, 10);
if (t > 0) ti = window.setTimeout(fwd, (t * 1000));
while (
e.offsetWidth > window.innerWidth ||
e.offsetHeight > window.innerHeight) {
e.style.fontSize = (i -= 2) + 'px';
if (i < 0) break;
}
e.style.marginTop = ((window.innerHeight - e.offsetHeight) / 2) + 'px';
if (window.location.hash !== n) window.location.hash = n;
document.title = e.textContent || e.innerText;
}
document.onclick = function() { go(++cur % (s.length)); };
function fwd() { go(Math.min(s.length - 1, ++cur)); }
function rev() { go(Math.max(0, --cur)); }
document.onkeydown = function(e) {
if (e.which === 39 || e.which === 34 || e.which === 40) fwd();
if (e.which === 37 || e.which === 33 || e.which === 38) rev();
};
document.ontouchstart = function(e) {
var x0 = e.changedTouches[0].pageX;
document.ontouchend = function(e) {
var x1 = e.changedTouches[0].pageX;
if (x1 - x0 < 0) fwd();
if (x1 - x0 > 0) rev();
};
};
function parse_hash() {
return Math.max(Math.min(
s.length - 1,
parseInt(window.location.hash.substring(1), 10)), 0);
}
if (window.location.hash) cur = parse_hash() || cur;
window.onhashchange = function() {
var c = parse_hash();
if (c !== cur) go(c);
};
go(cur);
};
</script></head><body>
<div><h2 id="build-fe-apps-the-mac-way">build FE apps the MAC way</h2>
<h4 id="model-action-component-">model, action, component*</h4>
<h5 id="-i-just-made-that-up">* i just made that up</h5>
</div>
<div><p><em>M</em>odels = API</p>
</div>
<div><p><em>A</em>ctions = Flux</p>
</div>
<div><p><em>C</em>omponents = React Views</p>
</div>
<div><p>Why is this different?</p>
</div>
<div><h2 id="mvc-or-mvvm-">MVC (or MVVM):</h2>
<ul>
<li>view code in separate files (incl. partials)</li>
<li>logic in views, too, at times</li>
<li>fat models</li>
<li>controllers* tend to contain event code</li>
</ul>
</div>
<div><h2 id="mac-flux-react-">MAC (Flux + React):</h2>
<ul>
<li>view and model code are in same place (<em>c</em>omponents)</li>
<li>events are <em>separate</em>, <em>one-way</em>, and <em>queueable</em></li>
<li>server (request-driven) and UI (user-driven) events are in one place</li>
</ul>
</div>
<div><h1 id="actions">Actions</h1>
<ul>
<li>Dispatched by, shockingly, a dispatcher</li>
<li>(usually EventEmitter subclass)</li>
</ul>
</div>
<div><h1 id="components">Components</h1>
<ul>
<li>View code in <code>render()</code></li>
<li>props as <code>this.props</code> (typesafe)</li>
<li>view logic in local functions</li>
</ul>
</div>
<div><h1 id="models">Models</h1>
<ul>
<li>Event driven too!</li>
<li>Loading locally? <code>POSTS_LOADED_EVENT</code></li>
<li>Loading via JSON request? <code>POSTS_LOADED_EVENT</code></li>
</ul>
</div>
<div><h2 id="for-example-post-component-">For example - Post Component:</h2>
<pre><code class="lang-javascript">Post = React.createClass({
render: function() {
return &lt;p className=&quot;post&quot;&gt;&lt;/p&gt;;
}
});
</code></pre>
</div>
<div><h2 id="blank-post-logic">Blank post logic</h2>
<pre><code class="lang-javascript">...
body: function() {
if (this.text &amp;&amp; this.text.length &gt; 0) {
return this.text;
} else {
return &quot;No content in this post.&quot;;
}
},
render: function() {
return (
&lt;p className=&quot;post&quot;&gt;
{this.body()}
&lt;/p&gt;
);
}
...
</code></pre>
</div>
<div><h3 id="one-more-piece-">One more piece!</h3>
<h1 id="stores">Stores</h1>
</div>
<div><h2 id="poststore">PostStore</h2>
<pre><code class="lang-javascript">// PostStore.js
var _posts = [];
var PostStore = assign({}, EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
});
...
</code></pre>
</div>
<div><h2 id="poststore">PostStore</h2>
<pre><code class="lang-javascript">// Farther down in PostStore.js
var token = PostStore.dispatchToken;
token = Dispatcher.register(function(action) {
switch (action.type) {
// ...
case ActionTypes.POST_CHANGED:
PostStore.updatePost(action.post);
Dispatcher.waitFor([OtherStore.dispatchToken]);
PostStore.emitChange();
break;
}
});
</code></pre>
</div>
<div><h1 id="in-summary">In Summary</h1>
<p>UI/Requests <em>create</em> Actions <em>in</em> Dispatcher, <em>which calls</em> Stores. Stores <em>trigger</em> Components.</p>
</div>
<div><h1 id="how-to-test">How to Test</h1>
<p>Just add synthetic events to your dispatcher. Then, unit test all your Stores, Components, etc.</p>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment