Skip to content

Instantly share code, notes, and snippets.

@colinyoung
Created July 9, 2015 16:43

Revisions

  1. colinyoung renamed this gist Jul 9, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. colinyoung created this gist Jul 9, 2015.
    192 changes: 192 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,192 @@
    <!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>