acdlite/flummox

View on GitHub
docs/dist/flummox/docs/guides/quick-start.md/index.html

Summary

Maintainability
Test Coverage
<!doctype html>
<html class="no-js" lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Flummox | Minimal, isomorphic Flux</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    
      <link rel="stylesheet" href="/flummox/css/app.min.css">
    
  </head>
  <body>
    <div id="app"><div data-reactid=".25s3ykyz0n4" data-react-checksum="1011138059"><div style="height:2.25rem;" class="View" data-reactid=".25s3ykyz0n4.0"><div class="View" style="background-color:#2083E0;position:fixed;width:100%;z-index:9999;" data-reactid=".25s3ykyz0n4.0.0"><div class="View" data-reactid=".25s3ykyz0n4.0.0.0"><div class="View" data-reactid=".25s3ykyz0n4.0.0.0.0"><a href="/" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.0.0.0">Flummox</a></div></div><div class="View View--justifyContentFlexEnd View--flexGrow" data-reactid=".25s3ykyz0n4.0.0.1"><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.0"><a href="/flummox/docs/guides" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.0.0">Guides</a><div class="View View--flexDirectionColumn" style="display:none;background-color:#2083E0;position:absolute;right:0;top:100%;width:16em;text-align:right;" data-reactid=".25s3ykyz0n4.0.0.1.0.1"><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.0.1.0"><a href="/flummox/docs/guides/quick-start" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.0.1.0.0">Quick Start</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.0.1.1"><a href="/flummox/docs/guides/react-integration" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.0.1.1.0">React Integration</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.0.1.2"><a href="/flummox/docs/guides/why-flux-component-is-better-than-flux-mixin" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.0.1.2.0">Why FluxComponent &gt; fluxMixin</a></div></div></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1"><a href="/flummox/docs/api" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.0">API</a><div class="View View--flexDirectionColumn" style="display:none;background-color:#2083E0;position:absolute;right:0;top:100%;width:16em;text-align:right;" data-reactid=".25s3ykyz0n4.0.0.1.1.1"><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1.1.0"><a href="/flummox/docs/api/store" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.1.0.0">Store</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1.1.1"><a href="/flummox/docs/api/flux" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.1.1.0">Flux</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1.1.2"><a href="/flummox/docs/api/actions" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.1.2.0">Actions</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1.1.3"><a href="/flummox/docs/api/fluxcomponent" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.1.3.0">FluxComponent</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1.1.4"><a href="/flummox/docs/api/higher-order-component" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.1.4.0">Higher-order component</a></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.1.1.5"><a href="/flummox/docs/api/fluxmixin" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.1.1.5.0">fluxMixin</a></div></div></div><div class="View" data-reactid=".25s3ykyz0n4.0.0.1.2"><a href="https://github.com/acdlite/flummox" style="padding:0.375rem 0.75rem;color:#fff;width:100%;text-decoration:none;border:inherit solid 1px;border-width:;border-style:;" data-reactid=".25s3ykyz0n4.0.0.1.2.0">GitHub</a></div></div></div></div><span data-reactid=".25s3ykyz0n4.1"><div data-reactid=".25s3ykyz0n4.1.$=1$/flummox/docs/guides/quick-start"><article class="Doc" style="padding:3rem 0;" data-reactid=".25s3ykyz0n4.1.$=1$/flummox/docs/guides/quick-start.0"><div class="Container" data-reactid=".25s3ykyz0n4.1.$=1$/flummox/docs/guides/quick-start.0.0"><div class="Doc-content" data-reactid=".25s3ykyz0n4.1.$=1$/flummox/docs/guides/quick-start.0.0.0"><h1>Quick start</h1>
<p>This document will help you get up and running with Flummox. We’ll walk through the process of creating a sample Flux application for sending messages.</p>
<p>Let’s dive right in.</p>
<h2>Installation</h2>
<p>This part’s pretty crucial :)</p>
<pre><code>$ npm install --save flummox
</code></pre>
<h2>Overview</h2>
<p>There are three parts to Flummox: Actions, Stores, and Flux. Each is represented by a class, and you extend from the base class.</p>
<p>Here’s how we’ll approach this walkthrough. I like to go in order of Flux data flow, because that just makes sense.</p>
<ol>
<li>Create some actions.</li>
<li>Create a store that responds to those actions.</li>
<li>Bring them together in a flux class.</li>
<li>Use it in a view.</li>
</ol>
<h3>1. Create some actions</h3>
<p>Actions are groups of functions you call to send data through the dispatcher. (Sometimes these are actually referred to as <em>action creators</em>, while actions are the data structures that are sent through the dispatcher, but whatever. We’re going to use <em>action</em> to refer to the function that triggers the dispatch.)</p>
<p>To create actions, just extend from the base Actions class and add some methods:</p>
<pre><code class="language-js">
import { Actions } from 'flummox';

class MessageActions extends Actions {

  createMessage(messageContent) {
    return {
      content: messageContent,
      date: Date.now(),
    };
  }

}

</code></pre>
<p>That’s it! Seriously. We just created a single action, <code>createMessage</code>, that takes in message content and returns an object with a message field and a date. The return value is then sent through the dispatcher automatically. (If you return <code>undefined</code>, Flummox skips the dispatch step.)</p>
<p>This is a pretty simple example, though. Often, your actions will need to perform some sort of async server operation before dispatching it to the stores. If you return a Promise, Flummox will wait for the Promise to resolve and then dispatch the unwrapped value. ES7’s async-await pattern makes this easy. Let’s update our example:</p>
<pre><code class="language-js">class MessageActions extends Actions {

  async createMessage(messageContent) {
    try {
      return await serverCreateMessage(messageContent);
    } catch (error) {
      // handle error somehow
    }
  }

}
</code></pre>
<p>You can also do this longhand without async-await, but why would you ever want to? Anyway, you have the option.</p>
<p>You may have noticed that we haven’t used any constants. “Hey, that’s not idiomatic Flux!” Flummox <em>does</em> have constants, but they’re treated as an implementation detail. Constants are generated for each action, and automatically sent through the dispatcher along with your payload. Because there’s a one-to-one relationship between constants and actions, in Flummox we refer to them as <em>action ids</em>. Generally, the only time you do need to worry about action ids is when you’re registering your stores to handle certain actions. Speaking of which…</p>
<h3>2. Create a store that responds to those actions</h3>
<p>Stores manage the state of your application. Usually, you have one store per resource or “thing” you want to keep track of — in our case, messages. The key thing to understand about stores is that they cannot (or rather, should not) be altered from the outside; they receive messages from the dispatcher and respond accordingly. If you’re new to Flux, this may seem like a distinction without a difference, but it’s crucial.</p>
<p>Here’s how you create a store in Flummox. Like with Actions, create a class that extends from the base class:</p>
<pre><code class="language-js">import { Store } from 'flummox';

class MessageStore extends Store {

  constructor(flux) {
    super(); // Don't forget this step

    const messageActionIds = flux.getActionIds('messages');
    this.register(messageActionIds.createMessage, this.handleNewMessage);

    this.state = {
      messages: [],
    };
  }

  handleNewMessage(message) {
    this.setState({
      messages: this.state.messages.concat([message]),
    });
  }

}
</code></pre>
<p>This should look very familiar to you if you’ve used ES6 classes to create components in React 0.13+:</p>
<ul>
<li>Like React, set initial state by assigning to <code>this.state</code> in the constructor.</li>
<li>Like React, update state by using <code>this.setState()</code>, which shallow merges new state with old state.</li>
<li>Like React, multiple calls to <code>this.setState()</code> are batched.</li>
</ul>
<p>Stores are EventEmitters. This lets views listen for changes and stay in sync. A change event is emitted automatically whenever you call <code>this.setState()</code>. If you like, you can also emit events manually using the EventEmitter API (<code>this.emit()</code>), though it’s recommended to just rely on <code>this.setState()</code>.</p>
<p>The one bit of API that’s new is <code>this.register(actionId, handler)</code>. This registers a store method with the dispatcher. Actually, it will accept any function, not just methods… but you probably want to stick to methods (except for testing purposes).</p>
<p>In this example, the store’s constructor expects a single argument, <code>flux</code>. This is not a required argument (notice we’re not passing it to <code>super()</code>); it’s a pattern we’re using so we have access to our message action ids. I’ll explain this in the next section.</p>
<h3>3. Bring them together in a flux class</h3>
<p>The Flux class unifies our stores and actions, along with a dispatcher, into a single, self-contained instance.</p>
<pre><code class="language-js">import { Flux } from 'flummox';

class AppFlux extends Flux {

  constructor() {
    super();

    this.createActions('messages', MessageActions);

    // The extra argument(s) are passed to the MessageStore constructor
    this.createStore('messages', MessageStore, this);
  }

}
</code></pre>
<p><code>createActions(key, ActionsClass, ...args)</code> and <code>createStore(key, StoreClass, ...args)</code> take a unique string key along with the classes we defined in the previous sections. There’s not much magic going on here: under the hood, Flummox creates instances of your classes using the <code>new</code> operator, then stashes a reference to them internally.</p>
<p>You can access a Flux instance’s actions and stores using <code>getActions(key)</code> and <code>getStore(key)</code>.</p>
<p>There’s an additional method for accessing action ids: <code>getActionIds(key)</code>. This is the method we used in the MessageStore class we created above, in order to register the store’s action handler. That’s why we’re passing our Flux instance to the constructor of MessageStore. To reiterate, this isn’t a requirement; just a recommended pattern.</p>
<p>Each Flux instance comes with its own dispatcher. Like constants, the dispatcher is treated as an implementation detail. The closest you’ll come to interacting with it in most cases is the <code>Store#register(actionId, handler)</code> method discussed above. However, if you want to access the dispatcher directly, you can reference the <code>dispatcher</code> property of the Flux instance.</p>
<p>So, now we have an AppFlux class that encapsulates our entire Flux set-up! Now we just create an instance:</p>
<pre><code class="language-js">const flux = new AppFlux();
</code></pre>
<p>Because everything is self-contained, you can create as many independent instances as you want. The reason this is so cool is that you get isomorphism for free: just create a new instance for each request.</p>
<h3>4. Use it in a view</h3>
<p>(Flummox/Flux can be used with any view library, of course, but I’m going to assume you’re cool and using React.)</p>
<p>So how do you use Flux in your view components? With a traditional Flux library, we’d use a singleton. And if you want to do that, that’s perfectly fine. Just create a module that exports a Flux instance and you’re good to go. But again, this won’t do on the server, because you need a way to 1) deal with multiple requests, and 2) isolate user-specific data. Instead, with Flummox, we create a new Flux instance for every request.</p>
<p>However, manually passing your Flux instance as props down the component tree isn’t the best solution. Instead, use fluxMixin and/or FluxComponent. Under the hood, they use React context to expose your Flux instance to arbitrarily nested views. They also make it stupidly easy to subscribe to store updates:</p>
<pre><code class="language-js">
class MessagesView extends React.Component {

  render() {
    return (
      &lt;FluxComponent connectToStores={{
        messages: store =&gt; ({
          messages: store.messages
        })
      }}&gt;
        // MessageList is injected with a `messages` prop by FluxContainer
        &lt;MessageList /&gt;
      &lt;/FluxComponent&gt;
    );
  }

}

</code></pre>
<p>Read more in the <a href="react-integration">React integration guide</a>.</p>
<p>And there you go! I hope this guide was helpful.</p>
</div></div></article></div></span></div></div>

    
      <script src="/flummox/js/app.min.js" defer></script>
    
  </body>
</html>