src/stores/FluxStore.js (62 lines of code) (raw):
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule FluxStore
 * @flow
 */
'use strict';
import type Dispatcher from 'Dispatcher';
const {EventEmitter} = require('fbemitter');
const invariant = require('invariant');
/**
 * This class represents the most basic functionality for a FluxStore. Do not
 * extend this store directly; instead extend FluxReduceStore when creating a
 * new store.
 */
class FluxStore {
  // private
  _dispatchToken: string;
  // protected, available to subclasses
  __changed: boolean;
  __changeEvent: string;
  __className: any;
  __dispatcher: Dispatcher<any>;
  __emitter: EventEmitter;
  constructor(dispatcher: Dispatcher<any>): void {
    this.__className = this.constructor.name;
    this.__changed = false;
    this.__changeEvent = 'change';
    this.__dispatcher = dispatcher;
    this.__emitter = new EventEmitter();
    this._dispatchToken = dispatcher.register((payload) => {
      this.__invokeOnDispatch(payload);
    });
  }
  addListener(callback: (eventType?: string) => void): {remove: () => void} {
    return this.__emitter.addListener(this.__changeEvent, callback);
  }
  getDispatcher(): Dispatcher<any> {
    return this.__dispatcher;
  }
  /**
   * This exposes a unique string to identify each store's registered callback.
   * This is used with the dispatcher's waitFor method to declaratively depend
   * on other stores updating themselves first.
   */
  getDispatchToken(): string {
    return this._dispatchToken;
  }
  /**
   * Returns whether the store has changed during the most recent dispatch.
   */
  hasChanged(): boolean {
    invariant(
      this.__dispatcher.isDispatching(),
      '%s.hasChanged(): Must be invoked while dispatching.',
      this.__className
    );
    return this.__changed;
  }
  __emitChange(): void {
    invariant(
      this.__dispatcher.isDispatching(),
      '%s.__emitChange(): Must be invoked while dispatching.',
      this.__className
    );
    this.__changed = true;
  }
  /**
   * This method encapsulates all logic for invoking __onDispatch. It should
   * be used for things like catching changes and emitting them after the
   * subclass has handled a payload.
   */
  __invokeOnDispatch(payload: Object): void {
    this.__changed = false;
    this.__onDispatch(payload);
    if (this.__changed) {
      this.__emitter.emit(this.__changeEvent);
    }
  }
  /**
   * The callback that will be registered with the dispatcher during
   * instantiation. Subclasses must override this method. This callback is the
   * only way the store receives new data.
   */
  __onDispatch(payload: Object): void {
    invariant(
      false,
      '%s has not overridden FluxStore.__onDispatch(), which is required',
      this.__className
    );
  }
}
module.exports = FluxStore;