Détail du package

alt

goatslacker76kMIT0.18.6

A flux implementation

alt, es6, flow, flux

readme

alt

Check out the API Reference for full in-depth docs. For a high-level walk-through on flux, take a look at the Getting Started guide. What follows below applies only to the master branch of alt and not the latest distribution. Any questions? ask in the gitter room.

Gitter

NPM version Build Status Coverage Status Dependency Status Download Count JS.ORG

Why you should be using Alt

  • It is pure flux. Stores have no setters, the flow is unidirectional.
  • Isomorphic and works with react-native.
  • Actively maintained and being used in production.
  • Extremely flexible and unopinionated in how you use flux. Create traditional singletons or use dependency injection.
  • It is terse. No boilerplate.

What does it look like?

Alt

import Alt from 'alt';
export default new Alt();

Actions

import alt from './alt';

class TodoActions {
  updateTodo(id, text) {
    return { id, text }
  }
}

export default alt.createActions(TodoActions);

Store

import alt from './alt';
import TodoActions from './TodoActions'

class TodoStore {
  constructor() {
    this.bindListeners({
      updateTodo: TodoActions.updateTodo
    });

    this.state = {
      todos: []
    };
  }

  updateTodo(todo) {
    this.setState({ todos: this.state.todos.concat(todo) });
  }
}

export default alt.createStore(TodoStore, 'TodoStore');

View

Using the connectToStores util from alt-utils package (npm install alt-utils)

// ES2015 (ES6)
import connectToStores from 'alt-utils/lib/connectToStores';
import { Component } from 'react';
import TodoStore from './TodoStore';

class TodoView extends Component {
  static getStores() {
    return [TodoStore];
  }

  static getPropsFromStores() {
    return TodoStore.getState();
  }

  render() {
    return (
      <ul>
        {this.props.todos.map((todo) => {
          return (
            <li key={todo.id}>{todo.text}</li>
          );
        })}
      </ul>
    );
  }
}
export default connectToStores(TodoView);

or

//ES2016 (ES7) using @connectToStores Decorator
import connectToStores from 'alt-utils/lib/connectToStores';
import { Component } from 'react';
import TodoStore from './TodoStore';

@connectToStores
class TodoView extends Component {
  static getStores() {
    return [TodoStore];
  }

  static getPropsFromStores() {
    return TodoStore.getState();
  }

  ...
}

In the Wild

Examples

Boilerplates

Pure Flux + More

  • Unidirectional data flow
  • Stores have no setters
  • Inversion of control
  • Single central dispatcher
  • All Stores receive the dispatch

Read about the Principles of Flux.

One really cool aspect of alt is that you can save snapshots of the entire application's state at any given point in time. This has many different use cases like:

  • Time traveling through the state of your application. For fun and profit.
  • Being able to debug from a broken state. Have your team send you the exact state the app was in when it crashed.
  • Isomorphism. You save a snapshot that you send from the server to the client and then bootstrap back on the client.
  • Rolling back to previous stable states.

There are also many utils available which interface well with alt:

  • ActionListener lets you listen to individual actions without having to create a store.
  • AltContainer a higher-order container component that is your swiss army knife for React.
  • AltIso addon that uses iso to render your application on both server and client.
  • atomic enables your stores for atomic transactions.
  • connectToStores a higher-order function that wraps your React components for store listening.
  • decorators a collection of useful ES7 decorators for working with alt.
  • DispatchRecorder lets you record all your dispatches and replay them back at a later time.
  • FinalStore is a Store that you can listen to that only emits when all your other stores have received all their data.
  • ImmutableUtil makes working with immutable-js easy.
  • TimeTravel enhances your stores so they are able to travel through different states in time.

Topical Guide

First we install alt through npm. Although alt is also available through bower.

npm install alt

The following topical guide covers on using alt as a singleton in a traditional flux way.

We'll be referring back to this code a lot by using the alt reference declared.

const Alt = require('alt');
const alt = new Alt();

ES6

Alt is written in, and encourages ES6. It is completely optional but it is pleasant to write.

You can use the es6 transpiler that comes with react courtesy of jstransform or you can use one of the other popular ES6 transpilers: babel or traceur.

You won't need an es6-shim but you can use one for further goodies in your javascripts.

Alt does depend on ES5 features, the good news is so does React. You can use es5-shim to support those pesky old browsers.

Typescript Definitions and Support

The typescript definitions for alt are located in the typings directory. This should be included in your project under typings/alt or whatever folder you use to manage your definitions files. You can import the dependencies react and es6-promises, easily with TSD. From here you can reference your typings as per usual with a reference tag <reference path="<path>.d.ts" />. Check the alt-typescript-tutorial for more information and project examples.

Using Typescript 1.5 you can import with the legacy syntax:

import Alt = require("alt");
import chromeDebug = require("alt/utils/chromeDebug");
import AltContainer = require("alt/AltContainer");

Creating Actions

Actions are the way you update state. They're kind of a big deal.

alt.createActions :: Class -> Actions

class LocationActions {
  updateLocation(city) {
    return city;
  }
}

const locationActions = alt.createActions(LocationActions);

You return the data from your action that you wish to dispatch. If you want to run async in your actions then you simply return a function where the first argument is the dispatch:

class LocationActions {
  updateLocationThatDoesItAsync(city) {
    return (dispatch) => {
      setTimeout(() => dispatch(city));
    };
  }
}

alt.createActions then returns an Object containing all the methods defined. You can then call your actions directly.

locationActions.updateLocation('Paris');

Writing out actions that pass data through directly can get quite tedious so there's a shorthand for writing these what are essentially identity functions

class LocationActions {
  constructor() {
    // for single action
    this.generateActions('updateLocation');

    // as well as for many actions
    this.generateActions('updateCity', 'updateCountry');
  }
}

const locationActions = alt.createActions(LocationActions);
locationActions.updateLocation('Las Vegas')

locationActions.updateCity('Las Vegas')
locationActions.updateCountry('US')

Remember, dispatch only takes one argument. Therefore, if you need to pass multiple arguments into a store you can use an Object.

class LocationActions {
  updateLocation(x, y) {
    return { x, y };
  }
}

const locationActions = alt.createActions(LocationActions);

locationActions.updateLocation('Miami', 'Florida');

A shorthand function created in the constructor will pass through the multiple parameters as an Array

class LocationActions {
  constructor() {
    this.generateActions('updateLocation'); // ['South Lake Tahoe, 'California']
  }
}

const locationActions = alt.createActions(LocationActions);

locationActions.updateLocation('South Lake Tahoe', 'California');

There's even a shorthand for the shorthand if all you're doing is generating a list of actions

const locationActions = alt.generateActions('updateLocation', 'updateCity', 'updateCountry');

Stores

Stores are where you keep a part of your application's state.

You can either define your stores as a class/constructor-prototype or as an Object.

alt.createStore :: Class, string -> Store

class LocationStore {
  constructor() {
    this.bindAction(locationActions.updateLocation, this.onUpdateLocation);

    this.state = {
      city: 'Denver',
      country: 'US'
    };
  }

  onUpdateLocation(obj) {
    const { city, country } = obj
    this.setState({ city, country });
  }
}

const locationStore = alt.createStore(LocationStore);

You can also use a regular old JavaScript Object to create your stores. This is more about aesthetic preference.

const locationStore = alt.createStore({
  displayName: 'LocationStore',

  bindListeners: {
    onUpdateLocation: locationActions.updateLocation
  },

  state: {
    city: 'Denver',
    country: 'US'
  },

  onUpdateLocation(obj) {
    const { city, country } = obj
    this.setState({ city, country });
  }
});

If you're creating a store using a class/constructor then you also have the option of assigning your state values to your instance directly and then you're able to update them in place.

function LocationStore() {
  this.city = 'San Francisco';
  this.country = 'US';
}

LocationStore.prototype.onUpdateLocation = function (obj) {
  this.city = obj.city;
  this.country = obj.country;
};

Store instances returned by alt.createStore can be listened to for updates by calling listen.

listen is meant to be used by your View components in order to await changes made to each store. It returns a function you can use to un-listen to your store.

locationStore.listen((data) => {
  console.log(data)
});

Alternatively, you can use the unlisten method. It takes in the same function you used for listen and unregisters it.

Another important method is getState, which returns a copy of the current store's state.

locationStore.getState().city === 'Denver'

Important Note

All defined methods in your Store class will not be available on the store instance. They are accessible within the class but not on the returned Object via alt.createStore. This ensures that stores have no direct setters and the state remains mutable only through actions keeping the flow unidirectional. If you want to attach public/static functions to your store the recommended method is to call the exportPublicMethods method from the constructor:

class LocationStore {
  constructor() {
    this.exportPublicMethods({
      myPublicMethod: this.myPublicMethod
    });
  }

  myPublicMethod() {
    const internalInstanceState = this.getState();
    return internalInstanceState;
  }
}

const locationStore = alt.createStore(LocationStore);

locationStore.myPublicMethod();

An alternative is to declare the method as static, which will cause alt to expose the method on the store:

// does the same thing as above except in a more magical way
class LocationStore {
  static myPublicMethod() {
    const internalInstanceState = this.getState();
    return internalInstanceState;
  }
}

Canceling An Event

If you don't want the store to inform the view of an action you can call this.preventDefault() (or you can return false) from inside an action handler method.

class LocationStore {
  constructor() {
    this.bindAction(locationActions.updateCity, this.onUpdateCity);

    this.state = {
      city: 'Portland',
      country: 'US'
    };
  }

  onUpdateCity(city) {
    this.setState({ city });

    // ensure the view never finds out
    this.preventDefault();
  }
}

const locationStore = alt.createStore(LocationStore);

Constants

I thought you said there were no constants? Well, yeah, sort of. The thing is, they're automagically created for you. Feel free to use them to bind your actions or use the method itself, whatever reads better in your opinion.

class LocationStore {
  constructor() {
    this.bindAction(locationActions.UPDATE_CITY, this.onUpdateCity);

    this.state = {
      city: '',
      country: ''
    };
  }
}

const locationStore = alt.createStore(LocationStore);

Listening To Multiple Actions

class LocationActions {
  constructor() {
    this.generateActions('updateCity', 'updateCountry');
  }
}

const locationActions = alt.createActions(LocationActions);

Using the function bindListeners you're able to specify which action handlers belong to which actions this way you have ultimate control over what gets called and handled.

The function bindListeners is the inverse of bindAction. bindListeners takes an object of action handlers as keys and actions as a value.

class LocationStore {
  constructor() {
    this.bindListeners({
      handleCity: locationActions.updateCity,
      handleCountry: [locationActions.updateCountry, locationActions.updateLatLng]
    });
  }

  handleCity(data) {
    // will only be called by locationActions.updateCity()
  }

  handleCountry(data) {
    // will be called by locationActions.updateCountry() and locationActions.updateLatLng()
  }
}

Alternatively, you can bind all the actions inside locationActions using the shortcut bindActions

class LocationStore {
  constructor() {
    this.bindActions(locationActions);

    this.state = {
      city: 'Austin',
      country: 'US'
    };
  }

  onUpdateCity(city) {
    this.setState({ city });
  }

  onUpdateCountry(country) {
    this.setState({ country });
  }
}

const locationStore = alt.createStore(LocationStore);

Actions who have a onCamelCasedAction method or an actionName method available in the store will be bound. In this example locationActions.updateCity will be handled by onUpdateCity. There is no difference between calling the action handler updateCity or onUpdateCity it's just a matter of aesthetic preference.

Managing Store Data Dependencies

waitFor is mostly an alias to Flux's Dispatcher waitFor. Here's an excerpt from the flux docs on what waitFor is designed for:

As an application grows, dependencies across different stores are a near certainty. Store A will inevitably need Store B to update itself first, so that Store A can know how to update itself. We need the dispatcher to be able to invoke the callback for Store B, and finish that callback, before moving forward with Store A. To declaratively assert this dependency, a store needs to be able to say to the dispatcher, "I need to wait for Store B to finish processing this action." The dispatcher provides this functionality through its waitFor() method.

You can use waitFor like so:

const dependingStore = alt.createStore(class DependingStore {
  constructor() {
    this.bindActions(someActions);

    this.state = { answer: 42 };
  }

  onRandom(answer) {
    this.setState({ answer });
  }
})

const locationStore = alt.createStore(class LocationStore {
  constructor() {
    this.bindActions(someOtherActions)

    this.state = {
      meaningOfLife: null
    };
  }

  onThings() {
    this.waitFor(dependingStore.dispatchToken);

    this.setState({ meaningOfLife: dependingStore.getState().answer });
  }
})

You can also waitFor multiple stores by passing in an Array: this.waitFor([store1.dispatchToken, store2.dispatchToken])

Views

Your choice of view isn't important to alt. What's important is to know how the view consumes the store's data, and that is via event listeners.

In this example I'll be using React, but you're free to use your library of choice.


class LocationView extends React.Component {
  // these are methods that work with `connectToStores` which connects
  // one or many stores to your component passing the state in as props.
  // you're free to choose how the state from the store is passed into the
  // component as props.

  // this automatically does the listening/unlistening for you as well as
  // handles the state changes
  static getStores() {
    return [locationStore];
  }

  static getPropsFromStores() {
    return locationStore.getState();
  }

  render() {
    return (
      <div>
        <p>
          City {this.props.city}
        </p>
        <p>
          Country {this.props.country}
        </p>
      </div>
    )
  }
}

// just make sure to wrap your component with connectToStores()
export default connectToStores(LocationView);

Full Circle

Restart the loop by making your views kick off new actions.

Alt Features

Snapshots

takeSnapshot :: ?...string -> string

Snapshots are a core component of alt. The idea is that at any given point in time you can takeSnapshot and have your entire application's state serialized for persistence, transferring, logging, or debugging.

Taking a snapshot is as easy as calling alt.takeSnapshot(). It can also take an optional number of arguments as strings which correspond to the store names you would like to include in the snapshot. This allows you to take a snapshot of a subset of your app's data.

Bootstrapping

bootstrap :: string -> undefined

Bootstrapping can be done as many times as you wish, but it is common to use when initializing your application. The alt.bootstrap() function takes in a snapshot (JSON string) you've saved and reloads all the state with that snapshot, no events will be emitted to your components during this process, so again, it's best to do this on init before the view has even rendered. If you need to emit a change event, you can use this.emitChange inside of your bootstrap life cycle method.

Bootstrap is great if you're running an isomorphic app, or if you're persisting state to localstorage and then retrieving it on init later on. You can save a snapshot on the server side, send it down, and then bootstrap it back on the client.

If you're bootstrapping then it is recommended you pass in a unique Identifier, name of the class is good enough, to createStore so that it can be referenced later for bootstrapping.

alt.createStore(LocationStore, 'LocationStore')

Rollback

rollback :: undefined

If you've screwed up the state, or you just feel like rolling back you can call alt.rollback(). Rollback is pretty dumb in the sense that it's not automatic in case of errors, and it only rolls back to the last saved snapshot, meaning you have to save a snapshot first in order to roll back.

Flushing

flush :: string

Flush takes a snapshot of the current state and then resets all the stores back to their original initial state. This is useful if you're using alt stores as singletons and doing server side rendering because of concurrency. In this particular scenario you would load the data in via bootstrap and then use flush to take a snapshot, render the data, and reset your stores so they are ready for the next request.

Recycling

recycle :: ?...string -> undefined

If you wish to reset a particular, or all, store's state back to their original initial state you would call recycle. Recycle takes an optional number of arguments as strings which correspond to the store's names you would like reset. If no argument is provided then all stores are reset.

Lifecycle Methods

When bootstrapping, snapshotting, or recycling there are special methods you can assign to your store to ensure any bookeeping that needs to be done. You would place these in your store's constructor.

bootstrap is called after the store has been bootstrapped. Here you can add some logic to take your bootstrapped data and manipulate it.

class Store {
  constructor() {
    this.on('bootstrap', () => {
      // do something here
    })
  }
}

init is called when the store is initialized as well as whenever a store is recycled.

class Store {
  constructor() {
    this.on('init', () => {
      // do something here
    })
  }
}

rollback is called whenever all the stores are rolled back.

class Store {
  constructor() {
    this.on('rollback', () => {
      // do something here
    })
  }
}

error is called whenever an error occurs in your store during a dispatch. You can use this listener to catch errors and perform any cleanup tasks.

class Store {
  constructor() {
    this.on('error', (err, actionName, payloadData, currentState) => {
      if (actionName === MyActions.fire) {
        logError(err, payloadData);
      }
    });

    this.bindListeners({
      handleFire: MyActions.fire
    });
  }

  handleFire() {
    throw new Error('Something is broken');
  }
}

See all the lifecycle methods

Single Dispatcher

A single dispatcher instance is made available for listening to all events passing through. You can access this via the dispatcher property: alt.dispatcher and listening to all events is as easy as

alt.dispatcher.register(console.log.bind(console))

Each store has a reference to the dispatcher as well

alt.createStore(class MyStore {
  constructor() {
    this.dispatcher.register(console.log.bind(console))
  }
})

Flexibility

You can choose to use alt in many ways just like you'd use flux. This means your asynchronous data fetching can live in the actions, or they can live in the stores. Stores may also be traditional singletons as in flux, or you can create an instance and have multiple store copies. This leads us into server side rendering.

Server Side Rendering

Alt was built with isomorphism in mind. This means that you can run full flux server-side and pick back up on the client-side.

There are two options for using flux on the server:

  • Keep stores as singletons, keep data loading synchronous, bootstrap, and flush.
  • Create multiple instances of flux and inject the context into your app.

Stores as Singletons

With this approach your stores are singletons. Any actions that load data must be synchronous, meaning you can fetch your data outside of actions and stores, and once done you fire off a synchronous action which loads the store. Alternatively, you can gather all of your data, and once complete, you call bootstrap() which seeds all the stores with some initial data.

Once you've completed loading the stores with data you call flush() which takes a snapshot to send to the client and then resets all the stores' state back to their initial state. This allows the stores to be ready for the next server request.

Flux Instances

Creating separate instances of flux rather than relying on singletons can help when building isomorphic applications.

The problem with singletons is that you need to manage them by clearing out all their state and reloading them with new state on every request because requests happen concurrently. This isn't a problem if you already have your data and just need to load it into flux, or if you don't want to share your data fetching logic with the client -- in which case you can just load all your data at once on the server and render once that is all complete.

Singletons only become a problem if you wish to share data fetching with client and server, don't want to use something like Render to define your data fetching at the component level, or if you have a really complex data fetching scheme where some fetches depend on the result of other ones. In these cases creating separate instances (or copies) keeps flux sandboxed to each request so other async requests won't mutate the state in the stores.

Taking this approach means you're making the trade-off of injecting the flux instance into your application in order to retrieve the stores and use the actions. This approach is similar to how fluxible solves isomorphic applications.

Creating a new alt instances is fairly simple.

class Flux extends Alt {
  constructor() {
    super();

    this.addActions('myActions', ActionCreators);
    this.addStore('storeName', Store);
  }
}

const flux = new Flux();
// client.js

React.render(
  <App flux={flux} />,
  document.body
);
// server.js
React.renderToString(<App flux={flux} />);
// retrieving stores
flux.getStore('storeName').getState();

// actions
flux.getActions('myActions');

Picking back up on the client

To help facilitate with isomorphism alt recommends you use iso, a helper function which serializes the data on the server into markup and then parses that data back into usable JavaScript on the client. Iso is a great complement to alt for a full-stack flux approach.

Converting a flux application to alt

  1. Importing the chat project.
  2. Adding alt and removing boilerplate.
  3. Converting some actions and the last action.
  4. Converting the stores MessageStore, ThreadStore, and UnreadThreadStore.
  5. Finishing touches.

Differences Example

Flux has constants, the dispatcher is also pretty dumb as in it just takes what you passed in the action and pipes it through to the store. This is completely fine but not something you should be expected to write. The nice thing about constants is that you can easily grep for them in your application and see where all the actions are being called, with alt you get the same benefit without having to manage them.

Before: Flux

var keyMirror = require('keymirror');

var actionConstants = keyMirror({
  HANDLE_ACTION: null
});

var action = {
  foo() {
    AppDispatcher.handleAction({ type: actionConstants.HANDLE_ACTION, data: 'foo' })
  }
};

var AppDispatcher = Object.assign(new Dispatcher(), {
  handleAction(payload) {
    this.dispatch(payload);
  }
});

After: Alt

class Action {
  handleAction() {
    return 'foo';
  }
}

const action = alt.createActions(Action);

TL;DR

  • Isomorphic
  • Pure Flux
  • No constants
  • No static string checking
  • No giant switch statement
  • Save state snapshots
  • Rollbacks
  • Bootstrap components on app load
  • Light-weight and terse
  • ES6 Syntax, code your actions and stores with classes
  • Flexible
  • No direct setters on stores
  • Single dispatcher
  • Global listening for debugging
  • Small library

License

MIT

changelog

Changelog

0.18.6

  • Fixes inheritance for actions #678

0.18.5

  • Updates transmitter which fixes #665

0.18.4

  • Upgrades babel and enables loose mode so IE10 can work again.

0.18.3

  • Removes cannot push while pushing error from transmitter.

0.18.2

  • Added jsnext:main so you can use rollup to bundle Alt. commit.
  • Fix returning promises from an action. commit.

0.18.0

Breaking Changes

  • Removed this.dispatch from Actions commit.

    Upgrade Guide

    • Use the included codemod to convert your actions.
    • You will need jscodeshift to run the codemod.
    • npm install jscodeshift -g
    • jscodeshift -t scripts/this-dispatch-to-return.js your_file.js
    • I recommend you use some source control like git this way you can git diff your changes and make sure everything is ok.

    • You can manually upgrade by removing this.dispatch from your actions and instead return your payload directly.

    • If you have an async action then you can return a function.
    // from this
    class MyActions {
      someAction() {
        this.dispatch(13)
      }
    }
    
    // to this
    class MyActions {
      someAction() {
        return 13
      }
    }

    or

    // from this
    class MyActions {
      asyncThings() {
        xhr('foo', () => {
          this.dispatch(42)
        })
      }
    }
    
    // to this
    class MyActions {
      asyncThings() {
        return (dispatch) => {
          xhr('foo', () => {
            dispatch(42)
          })
        }
      }
    }
  • Deleted all of utils, mixins, components, and addons from alt package.

    Upgrade Guide

    • Use the utils found here.
    • You can install these from npm.

Changed

  • isMutableObject checks for frozen Objects before updating them commit.

0.17.9

Changed

  • Fixes multiple actions from registering to the same handler commit.

0.17.8

Changed

  • Fix FSA dispatching commit
  • Stores created using an Object will now have a config. This gets rid of this issue. commit

0.17.7

Changed

  • isPojo renamed to isMutableObject. commit

  • This now checks if an object is frozen or not before attempting to delete keys from it.

0.17.6

Added

  • Can dispatch FSA actions directly through alt.dispatch. commit

0.17.5

Added

  • Makes alt FSA compliant. commit

Changed

  • Removes the warning if nothing is dispatched. commit
  • Fix regression for not setting state if reduce returns undefined. commit

0.17.4

Added

  • Allow dispatching action creators. commit
  • Warn if nothing is dispatched. commit
  • Pass store state to bootstrap lifecycle. commit
  • setState now handles values. commit
  • ImmutableUtil supports bootstrapping Records and more. commit

Changed

  • contextTypes are now copied onto connectToStores. commit
  • better typescript definitions. commit

0.17.3

Changed

  • Moved hot load delete of stores up to remove the warning shown in console. commit

0.17.2

Added

  • Add onMount handler for AltContainer. commit

  • Expose a reduce function for every store by default. commit

    If you're using reducers then this allows you to not ever use waitFor since you can just call store.reduce(store.getState(), payload) in order to derive data.

  • Allow values for store state. commit

    this.state can now be any valid JS value rather than always being an object.

  • Add some reducer utils. commit

    These reducer utils can be used for easily working with reducer only stores

Changed

  • Return value from sources local method. commit

  • Delete stores on hot reload. commit

    Working with react hot loader is now simpler.

  • Make fp tools faster by pulling directly from state. commit

  • Throw if listen does not get a function. commit

  • Change the connectToStores displayName. commit

  • Allow listening to same action with multiple methods. commit

0.17.1

Changed

  • Returning a promise from action no longer makes the action dispatch by default. commit

0.17.0

Breaking Changes

  • Removed Symbol

    Upgrade Guide

    • Remove all references to Symbol, Symbol.keyFor, etc.
    • Get access to the action's unique id via myAction.id
  • Removed getEventEmitter()

    Upgrade Guide

    • You can no longer access the internal event emitter to dispatch your own custom events. This is usually an anti-pattern.
    • If you still need this behavior you can create your own event emitter in your store.
class TodoStore {
  constructor() {
    this.eventEmitter = new EventEmitter()

    this.exportPublicMethods({
      getEventEmitter: () => this.eventEmitter
    });
  }
}
  • Removed _storeName.

    Upgrade Guide

    • _storeName was an internal property to the store where the store's name was kept.
    • You can now use displayName instead which is a public API.
  • Removed stateKey. commit

    Upgrade Guide

    • A stateKey property was configurable on stores as well as app level.
    • This has now been removed.
    • This key was mostly used so you can use the react-like API of this.state, now this is being supported first-class.
// old behavior
class MyStore {
  static config = { stateKey = 'state' }

  constructor() {
    this.state = {}
  }
}

Now you can just use this.state directly. If it exists it'll be picked up.

// old behavior
class MyStore {
  constructor() {
    this.state = {}
  }
}

The old behavior of assigning state directly as instance properties will continue to be supported. However, this new behavior will be favored in the docs.

  • Render.toString/toStaticMarkup now return an object rather than a string of html.

    Note: Render API is still in flux

    Upgrade Guide

// old
Render.toString(App, props).then(markup => console.log(markup))

// new
Render.toString(App, props).then(obj => console.log(obj.html))
  • Render.toDOM no longer locks by default.

    Upgrade Guide

    • Render.toDOM used to "lock" meaning it wouldn't perform the fetches on the client when it rendered.
    • Now this is configurable and off by default in case you want to use Render to render client side only.
// old
Render.toDOM(App, props, document.getElementById('react-root'))

// new
// the `true` is to not fetch client side.
Render.toDOM(App, props, document.getElementById('react-root'), true)

Added

  • A sweet new DispatcherDebugger react component which lets you debug your flux application on the browser. commit
  • You may now return from actions directly in order to dispatch, no need to call this.dispatch.
  • connectToStores can now be used where you specify the methods at the callsite. commit
  • statics addon lets you add your static methods to components that have been connected. commit
  • TypeScript definitions!. commit

Changed

  • Made the promise resolution to then(success, failure) so errors will be properly rejected. commit

0.16.10

Added

  • componentDidConnect for connectToStores. Allows you to specify data fetching in there. commit

  • Hot reload of stores using webpack. commit

Changed

  • Reversed the then/catch in the promise resolution for data sources so the catch only handles data source failures. commit

  • Throw when passing undefined to store.unlisten. commit

0.16.9

Added

  • preventDefault to stop a store from emitting a change. commit

  • observe() a way for POJOs to observe for changes. commit

  • otherwise() listen to all dispatches that have not been bound in your stores. commit

  • reduce() listen to all dispatches in a store and return the new state. commit

  • output() transform the output that is emitted from the stores. commit

  • Proper server rendering resolving all data at the component level before rendering. commit

  • Batched dispatches to avoid having componentWillMount cause a cannot dispatch while dispatching error when it loses context. commit

  • Alt.debug for registering your alt instance with chrome dev tools. commit

  • Function utils for transforming store state. commit

0.16.7

Added

  • interceptResponse method to data sources commit

Fixes

  • Revert breaking change back to merge state. 0.17.0 will include bootstrap, recycle, and flush replace state instead of merge state. commit

Changed

  • local method in data source must return null or undefined to trigger remote commit

0.16.6

Fixes

  • Fixes bug with recycle for keys that weren't set at the beginning. commit
  • Fixes isLoading for multiple async calls. commit

0.16.5

Added

  • @decorate(alt) to decorate your store and activate all @bind and @expose methods. commit
  • getStores in conenctToStores decorator/wrapper function now receives props from a store. commit
  • Solving the async debate. commit

0.16.4

Added

  • @bind and @expose decorators for binding actions and exporting public methods. commit
  • Made the lifecycles eventemitters so you can bind multiple. commit

Fixes

  • Bug with react-native. Stop using the Object.assign polyfill since react-native overrides it with a non-spec compliant one. commit

0.16.3

Dependencies

  • Updates es-symbol.

0.16.2

Added

  • Now passing more information through the dispatch about the action invoked. commit

0.16.1

This release is a pretty big one and it also marks Alt's first breaking changes.

Breaking Changes

Upgrade guide is included with each bullet point.

  • New method signatures for createStore, createActions, etc. commit

    Upgrade Guide

    • Previously all constructors for stores and actions received the alt instance as its first argument.
    • You now have to pass this in yourself.
// old behavior

class MyStore {
  constructor(alt) { }
}
// allows you to pass in your own arguments to the constructors

class MyStore {
  constructor(alt, one, two, three) { }
}

alt.createStore(MyStore, null, alt, 1, 2, 3)
  • beforeEach/afterEach methods have been moved to lifecycle. commit

    Upgrade Guide

    • Previously the beforeEach and afterEach methods existed as a prototype method on the store.
    • Now they are lifecycle methods.
// the new way

class Store {
  constructor() {
    this.on('beforeEach', () => {
    });
  }
}
  • withAltContext is now in decorator form. commit

    Upgrade Guide

    • Previously withAltContext took two arguments. The flux and the component.
    • Now it takes a single argument, flux. It returns a function which takes another argument, the component.

    As a decorator:

    @withAltContext(alt)
    export default class App extends React.Component {
      render() {
        return <div>{this.context.flux}</div>
      }
    }

    As a function:

    export default withAltContext(alt)(App);
  • Lifecycle method serialize and deserialize have been renamed and moved. commit

    Upgrade Guide

    • Rename serialize to onSerialize.
    • Rename deserialize to onDeserialize.
    • Move those methods to your Store's configuration.
    // new hotness
    class TodoStore {
      static config = {
        onSerialize() {
        },
    
        onDeserialize() {
        }
      }
    }
  • atomicTransactions util has been renamed to just atomic. commit

    Upgrade Guide

    • Change all your import/require from alt/util/atomicTransactions to alt/util/atomic
  • Removed mixins from browser-with-addons. commit

Mixins are dead, all hail our new higher-order component overlords. Please use AltContainer instead: http://alt.js.org/docs/components/altContainer/

  • Method signature for beforeEach, afterEach, error lifecycle events have changed. commit

    Upgrade Guide

    • Previously the method signature looked like fn(actionName, data, state).
    • Now it has been simplified to fn(payload, state) where payload is an object.
    • The payload object contains keys action and data which contain the information from before.
class Store {
  constructor() {
    this.on('beforeEach', (payload, state) => {
      console.log(payload.data);
    });
  }
}

Added

@timetravel
class TodoStore { }

TodoStore.undo(3);
TodoStore.redo(1);
  • connectToStores function which also works with decorators. commit
@connectToStores
class TodoApp extends React.Component {
  static getStores() {
    return [TodoStoreStore]
  }
  static getPropsFromStores(props) {
    return TodoStore.getState()
  }
  render() {
    return (
      <div>
        {this.props.todos.map(todo => <Todo todo={todo} />}
      </div>
    )
  }
}
  • ImmutableJS support, in an addon as a decorator. commit
@immutable
class TodoStore {
  constructor() {
    this.state = Immutable.Map({})
  }
}
  • Use store references to take snapshots. commit
alt.takeSnapshot(TodoStore); // returns only TodoStore's snapshot
  • Use store references to recycle. commit
alt.recycle(TodoStore); // recycles only TodoStore
  • Simple decorators for creating stores and actions. commit
import { createStore } from 'alt/utils/decorators'

@createStore(alt)
export default class TodoStore {
  constructor() {
  }
}
  • Apply transforms at the app level to modify each store before it is created. commit
alt.stateTransforms.push(Store => {
  // make every store atomic
  return atomic(alt)(Store)
})
  • Add specific configuration to your stores, like how getState and setState behave. commit
class TodoStore {
  static config = {
    getState(state) {
      // adds a new todo every time you getState
      return states.todos.push({ 'Another todo!' });
    }
  }
}
  • Create your actions inside the constructor by using instance properties. commit
class FooActions {
  constructor() {
    this.myAction = function (x) {
      this.dispatch(x);
    };
  }
}
  • All actions created are now available in alt.actions. commit

  • inject prop to AltContainer. commit

// inject lets you inject arbitrary props to your children

<AltContainer inject={{ foo: 7, bar: 'hello' }}>
  <div />
</AltContainer>

// div gets prop foo=7 and bar='hello'
  • component prop to AltContainer. commit

  • alt has a prepare method which prepares a payload for bootstrapping. commit

// rather than rendering its children you can now pass in a component

<AltContainer component={MyComponent} />

// equivalent to

<AltContainer>
  <MyComponent />
</AltContainer>
  • Allow customizing where you assign your state as a key. commit
// if you yearn for a react-like API you can now has

const alt = new Alt({ stateKey: 'state' });

class Store {
  constructor() {
    this.state = {
      stateGoesHere: 1,
      yay: 2
    };

    this.nowItsPrivate = true;
  }
}
// Customize the way getState and setState behave at the app level.

const alt = new Alt({
  getState(state) {
    // add fuzzlewuzzle to every state
    state.fuzzlewuzzle = true;
    return state;
  },

  setState(existingState, newState) {
    // forget existingState, in with the new out with the old
    return newState;
  }
});
  • Added maxEvents parameter to DispatcherRecorder. This allows you to specify how many events you wish to record. commit

Fixes

  • Performance improvement when creating a really large number of actions. commit
  • finalStore is cached per alt instance so it only returns one. commit
  • Override a store's name using displayName. commit
  • Fix context for nested components. commit
  • Fix AltContainer and AltNativeContainer's rendering. commit
  • setState now emits a change immediately if the dispatcher is not dispatching. commit

Changes

  • Internals were refactored. commit
  • Babel was upgraded to babel5. commit
  • Action symbols are now prefixed with alt/. commit

0.15.6

Added

  • Adding unlisten lifecycle method. commit
  • AltContainer now takes in store listeners for functions. commit
  • listen now returns the unlisten function. commit

0.15.5

Added

  • setState has been batched, it emits a change event if there were changes. commit
  • Util for having atomic transactions in stores. commit
  • AltNativeContainer for react-native. commit
  • Add shouldComponentUpdate to AltContainer. commit
  • Centralized error handling inside stores. commit
  • Creating single actions. commit
  • You can now inject actions into your child React components using AltContainer. commit
  • FinalStore now contains the payload as state. commit

0.15.4

Added

  • Chrome debugging exporter for devtool. commit

0.15.3

Added

  • Define your actions as POJO. commit
  • Use generateActions with alt instances. commit

0.15.2

Added/### Fixed

  • AltContainer can now receive new props and it'll change. commit

0.15.1

Fixed

  • A bug with AltContainer where it was using ES6 syntax. commit

0.15.0

Added

  • AltContainer which is a react container component that facilitates listening to stores and managing data. commit
  • beforeEach and afterEach hooks in stores for extending. commit
  • Allow custom dispatcher to be specified. commit
  • Adds serialize/loadEvents to the DispatcherRecorder. You can now transfer events between different alt instances and machines. commit
  • You can now get a list of a store's bound listeners with boundListeners. commit
  • Testing has been made even easier with access to the original store class with StoreModel. commit
  • takeSnapshot now allows you to take a snapshot of a single store. commit
  • rollback, flush, and recycle now emit change events. commit, commit
  • Adds AltManagerUtil which lets you manage multiple instances of alt. commit

Fixed

  • Fixes build on Windows. commit
  • If a non-store is passed to bootstrap it no longer crashes. commit
  • Added the snapshot method back in. commit

0.14.5

Fixed

  • Added react-native support. commit

0.14.4

Added

  • Create stores with a POJO. commit
  • Add serialize/deserialize lifecycle listener methods. commit
  • Add isomorphic rendering util. commit
  • emitChange method lets you emit directly from within a store without having to getInstance first. commit

Dev ### Dependencies

  • Update babel to 4.7.13. commit
  • Update eslint to 0.17.1 and remove babel-eslint. commit.

0.14.3

Added

  • exportPublicMethods can be used within a store to export public getter methods from the store. commit

Fixed

  • Future spec compliant change of making the derived store class call super before setting this. commit

0.14.2

Added

  • Browser builds for bower. commit

Changed

  • The store name generator is now more robust. commit

0.14.1

Dependencies

  • es-symbol has been updated to 1.1.1 commit

0.14.0

Changed

  • createStore no longer throws when it encounters a store with the same name. Instead if generates a new name for you and warns you in the console. If a store name is not specified due to using anonymous functions then a warning is also logged. commit

Dependencies

  • es-symbol has been updated to 1.1.0 for better IE8 compatibility. commit

0.13.11

Added

  • Added access to the internal EventEmitter used by the store. This can be access on the store instance by using getEventEmitter() and can be used for custom events. commit
  • Added a setState method for syntactic sugar which sets the state in the instance variables inside your store and then emits a change event. commit
  • Added emitChange method. No more this.getInstance().emitChange, now you can just this.emitChange() from inside a store. commit
  • Added syntactic sugar for waitFor. waitFor now takes in a splat or array of stores or dispatch tokens. commit
  • The alt instance now gets passed to the store constructor as well as the actions constructor. commit
  • ActionListener is a util that allows you to listen in on specific actions. Now it's even more lightweight if you want to listen in on a specific action but don't want the weight of a store. This comes as a util meaning it doesn't increase the size of core alt. Use it if you need it. commit

Fixed

  • addStore now has the saveStore parameter as well. commit

0.13.10

Added

  • DispatcherRecorder is a util that allows you to record and replay a series of actions. commit
  • FinalStore is a util Store that emits a change once all other stores have emitted. commit
  • Added a saveStore parameter to alt.createStore. This parameter controls whether we should save the store internally (for snapshots, bootstraps) or not. Default is true. commit

Fixed

  • All the mixins in the mixins folder don't make React complain about binding. commit

0.13.8

Added

  • Create context on add in Subscribe mixin. commit

Fixed

  • Change lifecycle hook for Listener mixin to ComponentWillMount so that it functions are identical between server rendering and client rendering. commit

0.13.7

Added

  • Add bindListeners method to Store. This is the inverse of bindActions. commit
  • Create shorthand form of createActions, generateActions. commit
  • Add/update several helpful mixins: FluxyMixin, ReactStateMagicMixin, and Subscribe. commit

0.13.4

Added

  • Add tests.

0.13.5

Added

  • Add bower.json to enable Alt with Bower. commit
  • Initial mixin pack addition. commit
  • ListenerMixin updated to listenTo various stores. commit

0.13.3

Dependencies

  • Upgrade to Babel 4.0 (formerly 6to5). commit

0.13.2

Added

  • Allow dispatching specific actions with any data. commit
  • Remove dispatcher symbol from actions. commit

Fixed

  • Assure that store instances do not collide. commit
  • Fix bug with defer where it is not variadic. commit

0.13.1

Added

  • Allow same action name on different Action Classes. commit

0.13.0

Added

  • Allow unlimited bootstraps. commit

0.12.0

Added

  • Replace lifecycle method API. commit
  • Add lifecycle methods, onBootstrapped and onRolledBack. commit
  • Distribute Alt with 6to5 runtime. commit
  • Allow creating many instances of Stores. commit

0.11.0

Dependencies

0.10.2

Added

  • Add a class to safeguard call checks. commit

0.10.1

Added

  • Add exportObj argument to createActions. commit

0.10.0

Added

  • Allow recycling of specific stores. commit

0.9.0

Added

  • Unlimited boostrapping on server. commit

0.8.0

Added

  • Add recycle and flush methods. commit
  • Make stores available in alt.stores. commit