Files
react/docs/flux-todo-list.html
T
2014-07-25 11:25:07 -07:00

1004 lines
68 KiB
HTML

<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>React | Flux TodoMVC Tutorial</title>
<meta name="viewport" content="width=device-width">
<meta property="og:title" content="React | Flux TodoMVC Tutorial">
<meta property="og:type" content="website">
<meta property="og:url" content="http://facebook.github.io/react/docs/flux-todo-list.html">
<meta property="og:image" content="http://facebook.github.io/react/img/logo_og.png">
<meta property="og:description" content="A JavaScript library for building user interfaces">
<meta property="fb:app_id" content="623268441017527">
<link rel="shortcut icon" href="/react/favicon.ico">
<link rel="alternate" type="application/rss+xml" title="React" href="http://facebook.github.io/react/feed.xml">
<link rel="stylesheet" href="/react/css/syntax.css">
<link rel="stylesheet" href="/react/css/codemirror.css">
<link rel="stylesheet" href="/react/css/react.css">
<script type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<!--[if lte IE 8]>
<script type="text/javascript" src="/react/js/html5shiv.min.js"></script>
<script type="text/javascript" src="/react/js/es5-shim.min.js"></script>
<script type="text/javascript" src="/react/js/es5-sham.min.js"></script>
<![endif]-->
<script type="text/javascript" src="/react/js/codemirror.js"></script>
<script type="text/javascript" src="/react/js/javascript.js"></script>
<script type="text/javascript" src="/react/js/react.js"></script>
<script type="text/javascript" src="/react/js/JSXTransformer.js"></script>
<script type="text/javascript" src="/react/js/live_editor.js"></script>
<script type="text/javascript" src="/react/js/showdown.js"></script>
</head>
<body>
<div class="container">
<div class="nav-main">
<div class="wrap">
<a class="nav-home" href="/react/index.html">
<img class="nav-logo" alt="" src="/react/img/logo_small.png" width="38" height="38">
React
</a>
<ul class="nav-site">
<li><a href="/react/docs/getting-started.html" class="active">docs</a></li>
<li><a href="/react/support.html">support</a></li>
<li><a href="/react/downloads.html">download</a></li>
<li><a href="/react/blog/">blog</a></li>
<li><a href="http://github.com/facebook/react">github</a>
</ul>
</div>
</div>
<section class="content wrap documentationContent">
<div class="nav-docs">
<!-- Docs Nav -->
<div class="nav-docs-section">
<h3>Quick Start</h3>
<ul>
<li>
<a href="/react/docs/getting-started.html">
Getting Started
</a>
</li>
<li>
<a href="/react/docs/tutorial.html">
Tutorial
</a>
</li>
<li>
<a href="/react/docs/thinking-in-react.html">
Thinking in React
</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Community Resources</h3>
<ul>
<li>
<a href="/react/docs/videos.html">
Videos
</a>
</li>
<li>
<a href="/react/docs/complementary-tools.html">
Complementary Tools
</a>
</li>
<li>
<a href="/react/docs/examples.html">
Examples
</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Guides</h3>
<ul>
<li>
<a href="/react/docs/why-react.html">
Why React?
</a>
</li>
<li>
<a href="/react/docs/displaying-data.html">
Displaying Data
</a>
<ul>
<li>
<a href="/react/docs/jsx-in-depth.html">
JSX in Depth
</a>
</li>
<li>
<a href="/react/docs/jsx-gotchas.html">
JSX Gotchas
</a>
</li>
</ul>
</li>
<li>
<a href="/react/docs/interactivity-and-dynamic-uis.html">
Interactivity and Dynamic UIs
</a>
</li>
<li>
<a href="/react/docs/multiple-components.html">
Multiple Components
</a>
</li>
<li>
<a href="/react/docs/reusable-components.html">
Reusable Components
</a>
</li>
<li>
<a href="/react/docs/forms.html">
Forms
</a>
</li>
<li>
<a href="/react/docs/working-with-the-browser.html">
Working With the Browser
</a>
<ul>
<li>
<a href="/react/docs/more-about-refs.html">
More About Refs
</a>
</li>
</ul>
</li>
<li>
<a href="/react/docs/tooling-integration.html">
Tooling Integration
</a>
</li>
<li>
<a href="/react/docs/addons.html">
Add-Ons
</a>
<ul>
<li>
<a href="/react/docs/animation.html">
Animation
</a>
</li>
<li>
<a href="/react/docs/two-way-binding-helpers.html">
Two-Way Binding Helpers
</a>
</li>
<li>
<a href="/react/docs/class-name-manipulation.html">
Class Name Manipulation
</a>
</li>
<li>
<a href="/react/docs/test-utils.html">
Test Utilities
</a>
</li>
<li>
<a href="/react/docs/clone-with-props.html">
Cloning Components
</a>
</li>
<li>
<a href="/react/docs/update.html">
Immutability Helpers
</a>
</li>
<li>
<a href="/react/docs/pure-render-mixin.html">
PureRenderMixin
</a>
</li>
<li>
<a href="/react/docs/perf.html">
Performance Tools
</a>
</li>
</ul>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Reference</h3>
<ul>
<li>
<a href="/react/docs/top-level-api.html">
Top-Level API
</a>
</li>
<li>
<a href="/react/docs/component-api.html">
Component API
</a>
</li>
<li>
<a href="/react/docs/component-specs.html">
Component Specs and Lifecycle
</a>
</li>
<li>
<a href="/react/docs/tags-and-attributes.html">
Supported Tags and Attributes
</a>
</li>
<li>
<a href="/react/docs/events.html">
Event System
</a>
</li>
<li>
<a href="/react/docs/dom-differences.html">
DOM Differences
</a>
</li>
<li>
<a href="/react/docs/special-non-dom-attributes.html">
Special Non-DOM Attributes
</a>
</li>
<li>
<a href="/react/docs/reconciliation.html">
Reconciliation
</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Flux</h3>
<ul>
<li>
<a href="/react/docs/flux-overview.html">
Flux Overview
</a>
</li>
<li>
<a href="/react/docs/flux-todo-list.html" class="active">
Flux Todo List
</a>
</li>
</ul>
</div>
<!-- Tips Nav -->
<div class="nav-docs-section">
<h3>Tips</h3>
<ul>
<li>
<a href="/react/tips/introduction.html">Introduction</a>
</li>
<li>
<a href="/react/tips/inline-styles.html">Inline Styles</a>
</li>
<li>
<a href="/react/tips/if-else-in-JSX.html">If-Else in JSX</a>
</li>
<li>
<a href="/react/tips/self-closing-tag.html">Self-Closing Tag</a>
</li>
<li>
<a href="/react/tips/maximum-number-of-jsx-root-nodes.html">Maximum Number of JSX Root Nodes</a>
</li>
<li>
<a href="/react/tips/style-props-value-px.html">Shorthand for Specifying Pixel Values in style props</a>
</li>
<li>
<a href="/react/tips/children-props-type.html">Type of the Children props</a>
</li>
<li>
<a href="/react/tips/controlled-input-null-value.html">Value of null for Controlled Input</a>
</li>
<li>
<a href="/react/tips/componentWillReceiveProps-not-triggered-after-mounting.html">componentWillReceiveProps Not Triggered After Mounting</a>
</li>
<li>
<a href="/react/tips/props-in-getInitialState-as-anti-pattern.html">Props in getInitialState Is an Anti-Pattern</a>
</li>
<li>
<a href="/react/tips/dom-event-listeners.html">DOM Event Listeners in a Component</a>
</li>
<li>
<a href="/react/tips/initial-ajax.html">Load Initial Data via AJAX</a>
</li>
<li>
<a href="/react/tips/false-in-jsx.html">False in JSX</a>
</li>
<li>
<a href="/react/tips/communicate-between-components.html">Communicate Between Components</a>
</li>
<li>
<a href="/react/tips/expose-component-functions.html">Expose Component Functions</a>
</li>
<li>
<a href="/react/tips/references-to-components.html">References to Components</a>
</li>
<li>
<a href="/react/tips/children-undefined.html">this.props.children undefined</a>
</li>
</ul>
</div>
</div>
<div class="inner-content">
<h1>
Flux TodoMVC Tutorial
<a class="edit-page-link" href="https://github.com/facebook/react/tree/master/docs/docs/flux-todo-list.md" target="_blank">Edit on GitHub</a>
</h1>
<div class="subHeader"></div>
<p>To demonstrate the Flux architecture with some example code, let&#39;s take on the classic TodoMVC application. The entire application is available in the React GitHub repo within the <a href="https://github.com/facebook/react/tree/master/examples/todomvc-flux">todomvc-flux</a> example directory, but let&#39;s walk through the development of it a step at a time. </p>
<p>To begin, we&#39;ll need some boilerplate and get up and running with a module system. Node&#39;s module system, based on CommonJS, will fit the bill very nicely and we can build off of <a href="https://github.com/petehunt/react-boilerplate">react-boilerplate</a> to get up and running quickly. Assuming you have npm installed, simply clone the react-boilerplate code from GitHub, and navigate into the resulting directory in Terminal (or whatever CLI application you like). Next run the npm scripts to get up and running: <code>npm install</code>, then <code>npm run build</code>, and lastly <code>npm start</code> to continuously build using Browserify.</p>
<p>The TodoMVC example has all this built into it as well, but if you&#39;re starting with react-boilerplate make sure you edit your package.json file to match the file structure and dependencies described in the TodoMVC example&#39;s <a href="https://github.com/facebook/react/tree/master/examples/todomvc-flux/package.json">package.json</a>, or else your code won&#39;t match up with the explanations below. </p>
<h2><a class="anchor" name="source-code-structure"></a>Source Code Structure <a class="hash-link" href="#source-code-structure">#</a></h2>
<p>The resulting index.js file may be used as the entry point into our app, but we&#39;ll put most of our code in a &#39;js&#39; directory. Let&#39;s let Browserify do its thing, and now we&#39;ll open a new tab in Terminal (or a GUI file browser) to look at the directory. It should look something like this: </p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">myapp
|
+ ...
+ js
|
+ app.js
+ bundle.js // generated by Browserify whenever we make changes.
+ index.html
+ ...
</code></pre></div>
<p>Next we&#39;ll dive into the js directory, and layout our application&#39;s primary directory structure: </p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">myapp
|
+ ...
+ js
|
+ actions
+ components // all React components, both views and controller-views
+ constants
+ dispatcher
+ stores
+ app.js
+ bundle.js
+ index.html
+ ...
</code></pre></div><h2><a class="anchor" name="creating-a-dispatcher-"></a>Creating a Dispatcher <a class="hash-link" href="#creating-a-dispatcher-">#</a></h2>
<p>Now we are ready to create a dispatcher. Here is an naive example of a Dispatcher class, written with JavaScript promises, polyfilled with Jake Archibald&#39;s <a href="https://github.com/jakearchibald/ES6-Promises">ES6-Promises</a> module. </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">Promise</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;es6-promise&#39;</span><span class="p">).</span><span class="nx">Promise</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">merge</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react/lib/merge&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">_callbacks</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">var</span> <span class="nx">_promises</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">var</span> <span class="nx">Dispatcher</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{};</span>
<span class="nx">Dispatcher</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="nx">merge</span><span class="p">(</span><span class="nx">Dispatcher</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
<span class="cm">/**</span>
<span class="cm"> * Register a Store&#39;s callback so that it may be invoked by an action.</span>
<span class="cm"> * @param {function} callback The callback to be registered.</span>
<span class="cm"> * @return {number} The index of the callback within the _callbacks array.</span>
<span class="cm"> */</span>
<span class="nx">register</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">_callbacks</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">_callbacks</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// index</span>
<span class="p">},</span>
<span class="cm">/**</span>
<span class="cm"> * dispatch</span>
<span class="cm"> * @param {object} payload The data from the action.</span>
<span class="cm"> */</span>
<span class="nx">dispatch</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// First create array of promises for callbacks to reference.</span>
<span class="kd">var</span> <span class="nx">resolves</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">var</span> <span class="nx">rejects</span> <span class="o">=</span> <span class="p">[];</span>
<span class="nx">_promises</span> <span class="o">=</span> <span class="nx">_callbacks</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">_</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">Promise</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">resolves</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">resolve</span><span class="p">;</span>
<span class="nx">rejects</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">reject</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="c1">// Dispatch to callbacks and resolve/reject promises.</span>
<span class="nx">_callbacks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">callback</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Callback can return an obj, to resolve, or a promise, to chain.</span>
<span class="c1">// See waitFor() for why this might be useful.</span>
<span class="nx">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="nx">callback</span><span class="p">(</span><span class="nx">payload</span><span class="p">)).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">resolves</span><span class="p">[</span><span class="nx">i</span><span class="p">](</span><span class="nx">payload</span><span class="p">);</span>
<span class="p">},</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">rejects</span><span class="p">[</span><span class="nx">i</span><span class="p">](</span><span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;Dispatcher callback unsuccessful&#39;</span><span class="p">));</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="nx">_promises</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">Dispatcher</span><span class="p">;</span>
</code></pre></div>
<p>The public API of this basic Dispatcher consists of only two methods: register() and dispatch(). We&#39;ll use register() within our stores to register each store&#39;s callback. We&#39;ll use dispatch() within our actions to trigger the invocation of the callbacks. </p>
<p>Now we are all set to create a dispatcher that is more specific to our app, which we&#39;ll call AppDispatcher. </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">Dispatcher</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./Dispatcher&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">merge</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react/lib/merge&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">AppDispatcher</span> <span class="o">=</span> <span class="nx">merge</span><span class="p">(</span><span class="nx">Dispatcher</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
<span class="cm">/**</span>
<span class="cm"> * A bridge function between the views and the dispatcher, marking the action</span>
<span class="cm"> * as a view action. Another variant here could be handleServerAction.</span>
<span class="cm"> * @param {object} action The data coming from the view.</span>
<span class="cm"> */</span>
<span class="nx">handleViewAction</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">action</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">dispatch</span><span class="p">({</span>
<span class="nx">source</span><span class="o">:</span> <span class="s1">&#39;VIEW_ACTION&#39;</span><span class="p">,</span>
<span class="nx">action</span><span class="o">:</span> <span class="nx">action</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">AppDispatcher</span><span class="p">;</span>
</code></pre></div>
<p>Now we&#39;ve created an implementation that is a bit more specific to our needs, with a helper function we can use in the actions coming from our views&#39; event handlers. We might expand on this later to provide a separate helper for server updates, but for now this is all we need. </p>
<h2><a class="anchor" name="creating-stores-"></a>Creating Stores <a class="hash-link" href="#creating-stores-">#</a></h2>
<p>We can use Node&#39;s EventEmitter to get started with a store. We need EventEmitter to broadcast the &#39;change&#39; event to our controller-views. So let&#39;s take a look at what that looks like. I&#39;ve omitted some of the code for the sake of brevity, but for the full version see <a href="https://github.com/Facebook/react/blob/master/examples/todomvc-flux/js/stores/TodoStore.js">TodoStore.js</a> in the TodoMVC example code. </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">AppDispatcher</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../dispatcher/AppDispatcher&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">EventEmitter</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;events&#39;</span><span class="p">).</span><span class="nx">EventEmitter</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">TodoConstants</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../constants/TodoConstants&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">merge</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react/lib/merge&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">CHANGE_EVENT</span> <span class="o">=</span> <span class="s1">&#39;change&#39;</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">_todos</span> <span class="o">=</span> <span class="p">{};</span> <span class="c1">// collection of todo items </span>
<span class="cm">/**</span>
<span class="cm"> * Create a TODO item. </span>
<span class="cm"> * @param {string} text The content of the TODO </span>
<span class="cm"> */</span>
<span class="kd">function</span> <span class="nx">create</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Using the current timestamp in place of a real id. </span>
<span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">();</span>
<span class="nx">_todos</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">id</span><span class="o">:</span> <span class="nx">id</span><span class="p">,</span>
<span class="nx">complete</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="nx">text</span><span class="o">:</span> <span class="nx">text</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="cm">/** </span>
<span class="cm"> * Delete a TODO item. </span>
<span class="cm"> * @param {string} id </span>
<span class="cm"> */</span>
<span class="kd">function</span> <span class="nx">destroy</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
<span class="k">delete</span> <span class="nx">_todos</span><span class="p">[</span><span class="nx">id</span><span class="p">];</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">TodoStore</span> <span class="o">=</span> <span class="nx">merge</span><span class="p">(</span><span class="nx">EventEmitter</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="p">{</span>
<span class="cm">/** </span>
<span class="cm"> * Get the entire collection of TODOs. </span>
<span class="cm"> * @return {object} </span>
<span class="cm"> */</span>
<span class="nx">getAll</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">_todos</span><span class="p">;</span>
<span class="p">},</span>
<span class="nx">emitChange</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="nx">CHANGE_EVENT</span><span class="p">);</span>
<span class="p">},</span>
<span class="cm">/** </span>
<span class="cm"> * @param {function} callback </span>
<span class="cm"> */</span>
<span class="nx">addChangeListener</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="nx">CHANGE_EVENT</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">},</span>
<span class="cm">/** </span>
<span class="cm"> * @param {function} callback </span>
<span class="cm"> */</span>
<span class="nx">removeChangeListener</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">CHANGE_EVENT</span><span class="p">,</span> <span class="nx">callback</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">dispatcherIndex</span><span class="o">:</span> <span class="nx">AppDispatcher</span><span class="p">.</span><span class="nx">register</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">payload</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">action</span> <span class="o">=</span> <span class="nx">payload</span><span class="p">.</span><span class="nx">action</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">text</span><span class="p">;</span>
<span class="k">switch</span><span class="p">(</span><span class="nx">action</span><span class="p">.</span><span class="nx">actionType</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="nx">TodoConstants</span><span class="p">.</span><span class="nx">TODO_CREATE</span><span class="o">:</span>
<span class="nx">text</span> <span class="o">=</span> <span class="nx">action</span><span class="p">.</span><span class="nx">text</span><span class="p">.</span><span class="nx">trim</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">text</span> <span class="o">!==</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">create</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span>
<span class="nx">TodoStore</span><span class="p">.</span><span class="nx">emitChange</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="nx">TodoConstants</span><span class="p">.</span><span class="nx">TODO_DESTROY</span><span class="o">:</span>
<span class="nx">destroy</span><span class="p">(</span><span class="nx">action</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
<span class="nx">TodoStore</span><span class="p">.</span><span class="nx">emitChange</span><span class="p">();</span>
<span class="k">break</span><span class="p">;</span>
<span class="c1">// add more cases for other actionTypes, like TODO_UPDATE, etc. </span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// No errors. Needed by promise in Dispatcher. </span>
<span class="p">})</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">TodoStore</span><span class="p">;</span>
</code></pre></div>
<p>There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from the outside. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action. </p>
<p>Another important part is the registration of the store&#39;s callback with the dispatcher. We pass in our payload handling callback to the dispatcher and preserve the index that this store has in the dispatcher&#39;s registry. The callback function currently only handles two actionTypes, but later we can add as many as we need. </p>
<h2><a class="anchor" name="listening-to-changes-with-a-controller-view-"></a>Listening to Changes with a Controller-View <a class="hash-link" href="#listening-to-changes-with-a-controller-view-">#</a></h2>
<p>We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook&#39;s Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface. Here&#39;s one for our TodoMVC example. Again, this is slightly abbreviated, but for the full code you can take a look at the TodoMVC example&#39;s <a href="https://github.com/facebook/react/blob/master/examples/todomvc-flux/js/components/TodoApp.react.js">TodoApp.react.js</a> </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** @jsx React.DOM */</span>
<span class="kd">var</span> <span class="nx">Footer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./Footer.react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">Header</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./Header.react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">MainSection</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./MainSection.react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">React</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoStore</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../stores/TodoStore&#39;</span><span class="p">);</span>
<span class="kd">function</span> <span class="nx">getTodoState</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="nx">allTodos</span><span class="o">:</span> <span class="nx">TodoStore</span><span class="p">.</span><span class="nx">getAll</span><span class="p">()</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">TodoApp</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="nx">getInitialState</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">getTodoState</span><span class="p">();</span>
<span class="p">},</span>
<span class="nx">componentDidMount</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">TodoStore</span><span class="p">.</span><span class="nx">addChangeListener</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">_onChange</span><span class="p">);</span>
<span class="p">},</span>
<span class="nx">componentWillUnmount</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">TodoStore</span><span class="p">.</span><span class="nx">removeChangeListener</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">_onChange</span><span class="p">);</span>
<span class="p">},</span>
<span class="cm">/**</span>
<span class="cm"> * @return {object}</span>
<span class="cm"> */</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">Header</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="nx">MainSection</span>
<span class="nx">allTodos</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">allTodos</span><span class="p">}</span>
<span class="nx">areAllComplete</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">areAllComplete</span><span class="p">}</span>
<span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="nx">Footer</span> <span class="nx">allTodos</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">allTodos</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/div&gt;</span>
<span class="p">);</span>
<span class="p">},</span>
<span class="nx">_onChange</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">(</span><span class="nx">getTodoState</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">TodoApp</span><span class="p">;</span>
</code></pre></div>
<p>Now we&#39;re in our familiar React territory, utilizing React&#39;s lifecycle methods. We set up the initial state of this controller-view in getInitialState(), register an event listener in componentDidMount(), and then clean up after ourselves within componentWillUnmount(). We render a containing div and pass down the collection of states we got from the TodoStore. </p>
<p>The Header component contains the primary text input for the application, but it does not need to know the state of the store. The MainSection and Footer do need this data, so we pass it down to them. </p>
<h2><a class="anchor" name="more-views-"></a>More Views <a class="hash-link" href="#more-views-">#</a></h2>
<p>At a high level, the React component hierarchy of the app looks like this: </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="o">&lt;</span><span class="nx">TodoApp</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">Header</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">TodoTextInput</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="nx">MainSection</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">ul</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">TodoItem</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/ul&gt; </span>
<span class="o">&lt;</span><span class="err">/MainSection&gt; </span>
<span class="o">&lt;</span><span class="err">/TodoApp&gt; </span>
</code></pre></div>
<p>If a TodoItem is in edit mode, it will also render a TodoTextInput as a child. Let&#39;s take a look at how some of these components display the data they receive as props, and how they communicate through actions with the dispatcher.
The MainSection needs to iterate over the collection of to-do items it received from TodoApp to create the list of TodoItems. In the component&#39;s render() method, we can do that iteration like so: </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">allTodos</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">allTodos</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">allTodos</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">todos</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="o">&lt;</span><span class="nx">TodoItem</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">key</span><span class="p">}</span> <span class="nx">todo</span><span class="o">=</span><span class="p">{</span><span class="nx">allTodos</span><span class="p">[</span><span class="nx">key</span><span class="p">]}</span> <span class="o">/&gt;</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">section</span> <span class="nx">id</span><span class="o">=</span><span class="s2">&quot;main&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">ul</span> <span class="nx">id</span><span class="o">=</span><span class="s2">&quot;todo-list&quot;</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">todos</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/ul&gt; </span>
<span class="p">);</span>
</code></pre></div>
<p>Now each TodoItem can display it&#39;s own text, and perform actions utilizing it&#39;s own ID. Explaining all the different actions that a TodoItem can invoke in the TodoMVC example goes beyond the scope of this article, but let&#39;s just take a look at the action that deletes one of the to-do items. Here is an abbreviated version of the TodoItem: </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** @jsx React.DOM */</span>
<span class="kd">var</span> <span class="nx">React</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoActions</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../actions/TodoActions&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoTextInput</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./TodoTextInput.react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoItem</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="nx">propTypes</span><span class="o">:</span> <span class="p">{</span>
<span class="nx">todo</span><span class="o">:</span> <span class="nx">React</span><span class="p">.</span><span class="nx">PropTypes</span><span class="p">.</span><span class="nx">object</span><span class="p">.</span><span class="nx">isRequired</span>
<span class="p">},</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">todo</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">todo</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">li</span>
<span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">label</span><span class="o">&gt;</span>
<span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span>
<span class="o">&lt;</span><span class="err">/label&gt; </span>
<span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&quot;destroy&quot;</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">_onDestroyClick</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/li&gt; </span>
<span class="p">);</span>
<span class="p">},</span>
<span class="nx">_onDestroyClick</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">TodoActions</span><span class="p">.</span><span class="nx">destroy</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">TodoItem</span><span class="p">;</span>
</code></pre></div>
<p>With a destroy action available in our library of TodoActions, and a store ready to handle it, connecting the user&#39;s interaction with application state changes could not be simpler. We just wrap our onClick handler around the destroy action, provide it with the id, and we&#39;re done. Now the user can click the destroy button and kick off the Flux cycle to update the rest of the application. </p>
<p>Text input, on the other hand, is just a bit more complicated because we need to hang on to the state of the text input within the React component itself. Let&#39;s take a look at how TodoTextInput works. </p>
<p>As you&#39;ll see below, with every change to the input, React expects us to update the state of the component. So when we are finally ready to save the text inside the input, we will put the value held in the component&#39;s state in the action&#39;s payload. This is UI state, rather than application state, and keeping that distinction in mind is a good guide for where state should live. All application state should live in the store, while components occasionally hold on to UI state. Ideally, React components preserve as little state as possible. </p>
<p>Because TodoTextInput is being used in multiple places within our application, with different behaviors, we&#39;ll need to pass the onSave method in as a prop from the component&#39;s parent. This allows onSave to invoke different actions depending on where it is used. </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** @jsx React.DOM */</span>
<span class="kd">var</span> <span class="nx">React</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">ReactPropTypes</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">PropTypes</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">ENTER_KEY_CODE</span> <span class="o">=</span> <span class="mi">13</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">TodoTextInput</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="nx">propTypes</span><span class="o">:</span> <span class="p">{</span>
<span class="nx">className</span><span class="o">:</span> <span class="nx">ReactPropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">,</span>
<span class="nx">id</span><span class="o">:</span> <span class="nx">ReactPropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">,</span>
<span class="nx">placeholder</span><span class="o">:</span> <span class="nx">ReactPropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">,</span>
<span class="nx">onSave</span><span class="o">:</span> <span class="nx">ReactPropTypes</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">isRequired</span><span class="p">,</span>
<span class="nx">value</span><span class="o">:</span> <span class="nx">ReactPropTypes</span><span class="p">.</span><span class="nx">string</span>
<span class="p">},</span>
<span class="nx">getInitialState</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="nx">value</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">value</span> <span class="o">||</span> <span class="s1">&#39;&#39;</span>
<span class="p">};</span>
<span class="p">},</span>
<span class="cm">/** </span>
<span class="cm"> * @return {object} </span>
<span class="cm"> */</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="cm">/*object*/</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">input</span>
<span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">className</span><span class="p">}</span>
<span class="nx">id</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span>
<span class="nx">placeholder</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">placeholder</span><span class="p">}</span>
<span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">_save</span><span class="p">}</span>
<span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">_onChange</span><span class="p">}</span>
<span class="nx">onKeyDown</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">_onKeyDown</span><span class="p">}</span>
<span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">value</span><span class="p">}</span>
<span class="nx">autoFocus</span><span class="o">=</span><span class="p">{</span><span class="kc">true</span><span class="p">}</span>
<span class="o">/&gt;</span>
<span class="p">);</span>
<span class="p">},</span>
<span class="cm">/** </span>
<span class="cm"> * Invokes the callback passed in as onSave, allowing this component to be </span>
<span class="cm"> * used in different ways. </span>
<span class="cm"> */</span>
<span class="nx">_save</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">onSave</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span>
<span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;&#39;</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="cm">/** </span>
<span class="cm"> * @param {object} event </span>
<span class="cm"> */</span>
<span class="nx">_onChange</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="cm">/*object*/</span> <span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span>
<span class="nx">value</span><span class="o">:</span> <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="cm">/** </span>
<span class="cm"> * @param {object} event </span>
<span class="cm"> */</span>
<span class="nx">_onKeyDown</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">ENTER_KEY_CODE</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">_save</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">TodoTextInput</span><span class="p">;</span>
</code></pre></div>
<p>The Header passes in the onSave method as a prop to allow the TodoTextInput to create new
to-do items: </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** @jsx React.DOM */</span>
<span class="kd">var</span> <span class="nx">React</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoActions</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../actions/TodoActions&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoTextInput</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./TodoTextInput.react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">Header</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="cm">/**</span>
<span class="cm"> * @return {object}</span>
<span class="cm"> */</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">header</span> <span class="nx">id</span><span class="o">=</span><span class="s2">&quot;header&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">h1</span><span class="o">&gt;</span><span class="nx">todos</span><span class="o">&lt;</span><span class="err">/h1&gt;</span>
<span class="o">&lt;</span><span class="nx">TodoTextInput</span>
<span class="nx">id</span><span class="o">=</span><span class="s2">&quot;new-todo&quot;</span>
<span class="nx">placeholder</span><span class="o">=</span><span class="s2">&quot;What needs to be done?&quot;</span>
<span class="nx">onSave</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">_onSave</span><span class="p">}</span>
<span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/header&gt;</span>
<span class="p">);</span>
<span class="p">},</span>
<span class="cm">/**</span>
<span class="cm"> * Event handler called within TodoTextInput.</span>
<span class="cm"> * Defining this here allows TodoTextInput to be used in multiple places</span>
<span class="cm"> * in different ways.</span>
<span class="cm"> * @param {string} text</span>
<span class="cm"> */</span>
<span class="nx">_onSave</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">TodoActions</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">Header</span><span class="p">;</span>
</code></pre></div>
<p>In a different context, such as in editing mode for an existing to-do item, we might pass an onSave callback that invokes <code>TodoActions.update(text)</code> instead. </p>
<h2><a class="anchor" name="creating-semantic-actions-"></a>Creating Semantic Actions <a class="hash-link" href="#creating-semantic-actions-">#</a></h2>
<p>Here is the basic code for the two actions we used above in our views: </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** </span>
<span class="cm"> * TodoActions </span>
<span class="cm"> */</span>
<span class="kd">var</span> <span class="nx">AppDispatcher</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../dispatcher/AppDispatcher&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoConstants</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../constants/TodoConstants&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoActions</span> <span class="o">=</span> <span class="p">{</span>
<span class="cm">/**</span>
<span class="cm"> * @param {string} text</span>
<span class="cm"> */</span>
<span class="nx">create</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">AppDispatcher</span><span class="p">.</span><span class="nx">handleViewAction</span><span class="p">({</span>
<span class="nx">actionType</span><span class="o">:</span> <span class="nx">TodoConstants</span><span class="p">.</span><span class="nx">TODO_CREATE</span><span class="p">,</span>
<span class="nx">text</span><span class="o">:</span> <span class="nx">text</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="cm">/**</span>
<span class="cm"> * @param {string} id</span>
<span class="cm"> */</span>
<span class="nx">destroy</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">AppDispatcher</span><span class="p">.</span><span class="nx">handleViewAction</span><span class="p">({</span>
<span class="nx">actionType</span><span class="o">:</span> <span class="nx">TodoConstants</span><span class="p">.</span><span class="nx">TODO_DESTROY</span><span class="p">,</span>
<span class="nx">id</span><span class="o">:</span> <span class="nx">id</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="p">};</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">TodoActions</span><span class="p">;</span>
</code></pre></div>
<p>As you can see, we really would not need to have the helpers AppDispatcher.handleViewAction() or TodoActions.create(). We could, in theory, call AppDispatcher.dispatch() directly and provide a payload. But as our application grows, having these helpers keeps the code clean and semantic. It&#39;s just a lot cleaner to write TodoActions.destroy(id) instead of writing a whole lot of things that our TodoItem shouldn&#39;t have to know about. </p>
<p>The payload produced by the TodoActions.create() will look like: </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="p">{</span>
<span class="nx">source</span><span class="o">:</span> <span class="s1">&#39;VIEW_ACTION&#39;</span><span class="p">,</span>
<span class="nx">action</span><span class="o">:</span> <span class="p">{</span>
<span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;TODO_CREATE&#39;</span><span class="p">,</span>
<span class="nx">text</span><span class="o">:</span> <span class="s1">&#39;Write blog post about Flux&#39;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>This payload is provided to the TodoStore through its registered callback. The TodoStore then broadcasts the &#39;change&#39; event, and the MainSection responds by fetching the new collection of to-do items from the TodoStore and changing its state. This change in state causes the TodoApp component to call its own render() method, and the render() method of all of its descendents. </p>
<h2><a class="anchor" name="start-me-up-"></a>Start Me Up <a class="hash-link" href="#start-me-up-">#</a></h2>
<p>The bootstrap file of our application is app.js. It simply takes the TodoApp component and renders it in the root element of the application. </p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** @jsx React.DOM */</span>
<span class="kd">var</span> <span class="nx">React</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;react&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">TodoApp</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./components/TodoApp.react&#39;</span><span class="p">);</span>
<span class="nx">React</span><span class="p">.</span><span class="nx">renderComponent</span><span class="p">(</span>
<span class="o">&lt;</span><span class="nx">TodoApp</span> <span class="o">/&gt;</span><span class="p">,</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;todoapp&#39;</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div><h2><a class="anchor" name="adding-dependency-management-to-the-dispatcher-"></a>Adding Dependency Management to the Dispatcher <a class="hash-link" href="#adding-dependency-management-to-the-dispatcher-">#</a></h2>
<p>As I said previously, our Dispatcher implementation is a bit naive. It&#39;s pretty good, but it will not suffice for most applications. We need a way to be able to manage dependencies between Stores. Let&#39;s add that functionality with a waitFor() method within the main body of the Dispatcher class. </p>
<p>We&#39;ll need another public method, waitFor(). Note that it returns a Promise that can in turn be returned from the Store callback.</p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"> <span class="cm">/**</span>
<span class="cm"> * @param {array} promisesIndexes</span>
<span class="cm"> * @param {function} callback</span>
<span class="cm"> */</span>
<span class="nx">waitFor</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">promiseIndexes</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">selectedPromises</span> <span class="o">=</span> <span class="nx">promiseIndexes</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">_promises</span><span class="p">[</span><span class="nx">index</span><span class="p">];</span>
<span class="p">});</span>
<span class="k">return</span> <span class="nx">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">(</span><span class="nx">selectedPromises</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="nx">callback</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>Now within the TodoStore callback we can explicitly wait for any dependencies to first update before moving forward. However, if Store A waits for Store B, and B waits for A, then a circular dependency will occur. A more robust dispatcher is required to flag this scenario with warnings in the console.</p>
<h2><a class="anchor" name="the-future-of-flux-"></a>The Future of Flux <a class="hash-link" href="#the-future-of-flux-">#</a></h2>
<p>A lot of people ask if Facebook will release Flux as an open source framework. Really, Flux is just an architecture, not a framework. But perhaps a Flux boilerplate project might make sense, if there is enough interest. Please let us know if you&#39;d like to see us do this.</p>
<p>Thanks for taking the time to read about how we build client-side applications at Facebook. We hope Flux proves as useful to you as it has to us.</p>
<div class="docs-prevnext">
<a class="docs-prev" href="/react/docs/flux-overview.html">&larr; Prev</a>
</div>
</div>
</section>
<footer class="wrap">
<div class="left">
A Facebook &amp; Instagram collaboration.<br>
<a href="/react/acknowledgements.html">Acknowledgements</a>
</div>
<div class="right">&copy; 2014 Facebook Inc.</div>
</footer>
</div>
<div id="fb-root"></div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-41298772-1', 'facebook.github.io');
ga('send', 'pageview');
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=623268441017527";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
</body>
</html>