Created
July 9, 2015 16:43
-
-
Save colinyoung/0c0bfea10431d56682c7 to your computer and use it in GitHub Desktop.
React talk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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 <p className="post"></p>; | |
} | |
}); | |
</code></pre> | |
</div> | |
<div><h2 id="blank-post-logic">Blank post logic</h2> | |
<pre><code class="lang-javascript">... | |
body: function() { | |
if (this.text && this.text.length > 0) { | |
return this.text; | |
} else { | |
return "No content in this post."; | |
} | |
}, | |
render: function() { | |
return ( | |
<p className="post"> | |
{this.body()} | |
</p> | |
); | |
} | |
... | |
</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