{"id":13437702,"url":"https://github.com/goatslacker/alt","last_synced_at":"2025-05-13T23:09:37.223Z","repository":{"id":24809444,"uuid":"28223616","full_name":"goatslacker/alt","owner":"goatslacker","description":"Isomorphic flux implementation","archived":false,"fork":false,"pushed_at":"2023-03-28T22:15:12.000Z","size":3832,"stargazers_count":3441,"open_issues_count":128,"forks_count":319,"subscribers_count":63,"default_branch":"master","last_synced_at":"2025-04-30T10:36:45.892Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://alt.js.org/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goatslacker.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2014-12-19T09:44:04.000Z","updated_at":"2025-04-17T01:52:20.000Z","dependencies_parsed_at":"2022-08-23T07:11:02.753Z","dependency_job_id":"4886893f-1fc1-4205-a61e-27157dc1530b","html_url":"https://github.com/goatslacker/alt","commit_stats":{"total_commits":1074,"total_committers":100,"mean_commits":10.74,"dds":"0.24115456238361266","last_synced_commit":"d4cd64938d249463e9717426d223eba49d8a0fc2"},"previous_names":[],"tags_count":68,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goatslacker%2Falt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goatslacker%2Falt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goatslacker%2Falt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goatslacker%2Falt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goatslacker","download_url":"https://codeload.github.com/goatslacker/alt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254042177,"owners_count":22004861,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:00:59.444Z","updated_at":"2025-05-13T23:09:32.175Z","avatar_url":"https://github.com/goatslacker.png","language":"JavaScript","readme":"# alt\n\nCheck out the [API Reference](http://alt.js.org/docs/) for full in-depth docs. For a high-level walk-through on flux, take a look at the [Getting Started](http://alt.js.org/guide/) guide. What follows below applies only to the master branch of `alt` and not the latest distribution. Any questions? ask in the gitter room.\n\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/goatslacker/alt?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n[![NPM version](https://badge.fury.io/js/alt.svg)](http://badge.fury.io/js/alt)\n[![Build Status](https://secure.travis-ci.org/goatslacker/alt.svg?branch=master)](http://travis-ci.org/goatslacker/alt)\n[![Coverage Status](https://img.shields.io/coveralls/goatslacker/alt.svg?style=flat)](https://coveralls.io/r/goatslacker/alt)\n[![Dependency Status](https://david-dm.org/goatslacker/alt.svg)](https://david-dm.org/goatslacker/alt)\n[![Download Count](https://img.shields.io/npm/dm/alt.svg?style=flat)](https://www.npmjs.com/package/alt)\n[![JS.ORG](https://img.shields.io/badge/js.org-alt-ffb400.svg?style=flat-square)](http://js.org)\n\n### Why you should be using Alt\n\n* It is pure [flux](http://facebook.github.io/flux/docs/overview.html). Stores have no setters, the flow is unidirectional.\n* Isomorphic and works with react-native.\n* Actively maintained and being used in production.\n* Extremely [flexible](#flexibility) and unopinionated in how you use flux. Create traditional singletons or use dependency injection.\n* It is terse. No boilerplate.\n\n### What does it look like?\n\nAlt\n\n```js\nimport Alt from 'alt';\nexport default new Alt();\n```\n\nActions\n\n```js\nimport alt from './alt';\n\nclass TodoActions {\n  updateTodo(id, text) {\n    return { id, text }\n  }\n}\n\nexport default alt.createActions(TodoActions);\n```\n\nStore\n\n```js\nimport alt from './alt';\nimport TodoActions from './TodoActions'\n\nclass TodoStore {\n  constructor() {\n    this.bindListeners({\n      updateTodo: TodoActions.updateTodo\n    });\n\n    this.state = {\n      todos: []\n    };\n  }\n\n  updateTodo(todo) {\n    this.setState({ todos: this.state.todos.concat(todo) });\n  }\n}\n\nexport default alt.createStore(TodoStore, 'TodoStore');\n```\n\nView \n\nUsing the [connectToStores](https://github.com/altjs/utils/blob/master/src/connectToStores.js) util from [alt-utils](https://github.com/altjs/utils) package (`npm install alt-utils`)\n\n```js\n// ES2015 (ES6)\nimport connectToStores from 'alt-utils/lib/connectToStores';\nimport { Component } from 'react';\nimport TodoStore from './TodoStore';\n\nclass TodoView extends Component {\n  static getStores() {\n    return [TodoStore];\n  }\n\n  static getPropsFromStores() {\n    return TodoStore.getState();\n  }\n\n  render() {\n    return (\n      \u003cul\u003e\n        {this.props.todos.map((todo) =\u003e {\n          return (\n            \u003cli key={todo.id}\u003e{todo.text}\u003c/li\u003e\n          );\n        })}\n      \u003c/ul\u003e\n    );\n  }\n}\nexport default connectToStores(TodoView);\n```\nor\n```js\n//ES2016 (ES7) using @connectToStores Decorator\nimport connectToStores from 'alt-utils/lib/connectToStores';\nimport { Component } from 'react';\nimport TodoStore from './TodoStore';\n\n@connectToStores\nclass TodoView extends Component {\n  static getStores() {\n    return [TodoStore];\n  }\n\n  static getPropsFromStores() {\n    return TodoStore.getState();\n  }\n\n  ...\n}\n```\n\n## In the Wild\n\n### Examples\n\n* [Airbnb Airpal](https://github.com/airbnb/airpal/tree/master/src/main/resources/assets)\n* [Alt Notify](https://github.com/sourcescript/alt-notify)\n* [Chrome Devtool](https://github.com/goatslacker/alt-devtool)\n* [Example Tests](https://github.com/jdlehman/alt-example-tests)\n* [Github Example](https://github.com/RookieOne/react-alt-github-example)\n* [Isomorphic Alt](https://github.com/patrickkim/iso-alt)\n* [Jumar's Tindahan](https://github.com/chirigarikku/jumars-tindahan)\n* [Maple.js Webcomponents](https://github.com/Wildhoney/Maple.js/tree/master/example/app)\n* [React Native Example](https://github.com/mrblueblue/react-native-alt-demo)\n* [React Router Example](https://github.com/lostpebble/alt-react-router-example)\n* [React Router Loopback](https://github.com/bkniffler/react-router-alt-loopback)\n* [React Webpack Rails Example](https://github.com/shakacode/react-webpack-rails-tutorial)\n* [React Webpack Altjs Example](https://underthehood.myob.com/changing-of-the-guard-in-web-technologies/)\n* [React Weather](https://github.com/sapegin/react-weather)\n* [Shopping Cart](https://github.com/voronianski/flux-comparison/tree/master/alt)\n* [Todo](https://github.com/benstokoe/alt-todo)\n* [Typeahead](https://github.com/timtyrrell/alt-typeahead)\n* [Isomorphic React Examples](https://github.com/goatslacker/isomorphic-react-examples)\n* [Typescript Project](https://github.com/Shearerbeard/alt-typescript-tutorial)\n* [Why did Social Tables choose Alt?](https://medium.com/social-tables-tech/we-compared-13-top-flux-implementations-you-won-t-believe-who-came-out-on-top-1063db32fe73)\n\n### Boilerplates\n\n* [Isomorphic Flux Boilerplate](https://github.com/iam4x/isomorphic-flux-boilerplate)\n* [React + Webpack + Node](https://github.com/choonkending/react-webpack-node/tree/flux/alt)\n* [Web-React](https://github.com/darul75/web-react)\n* [Generator-React-Webpack-Alt](https://github.com/weblogixx/generator-react-webpack-alt)\n* [Isomorphic Alt Generator](https://www.npmjs.com/package/generator-iso-alt)\n\n## Pure Flux + More\n\n* Unidirectional data flow\n* Stores have no setters\n* Inversion of control\n* Single central dispatcher\n* All Stores receive the dispatch\n\nRead about the [Principles of Flux](https://medium.com/@goatslacker/principles-of-flux-ea872bc20772).\n\nOne really cool aspect of alt is that you can save snapshots of the entire application's state at any given point in time.\nThis has many different use cases like:\n\n* Time traveling through the state of your application. For fun and profit.\n* Being able to debug from a broken state. Have your team send you the exact state the app was in when it crashed.\n* Isomorphism. You save a snapshot that you send from the server to the client and then bootstrap back on the client.\n* Rolling back to previous stable states.\n\nThere are also many [utils](https://github.com/altjs/utils) available which interface well with alt:\n\n* [ActionListener](https://github.com/altjs/utils/blob/master/src/ActionListeners.js) lets you listen to individual actions without having to create a store.\n* [AltContainer](https://github.com/altjs/container) a higher-order container component that is your swiss army knife for React.\n* [AltIso](https://github.com/altjs/utils/blob/master/src/AltIso.js) addon that uses [iso](https://github.com/goatslacker/iso) to render your application on both server and client.\n* [atomic](https://github.com/altjs/utils/blob/master/src/atomic.js) enables your stores for atomic transactions.\n* [connectToStores](https://github.com/altjs/connect-to-stores) a higher-order function that wraps your React components for store listening.\n* [decorators](https://github.com/altjs/utils/blob/master/src/decorators.js) a collection of useful ES7 decorators for working with alt.\n* [DispatchRecorder](https://github.com/altjs/utils/blob/master/src/DispatcherRecorder.js) lets you record all your dispatches and replay them back at a later time.\n* [FinalStore](https://github.com/altjs/utils/blob/master/src/makeFinalStore.js) is a Store that you can listen to that only emits when all your other stores have received all their data.\n* [ImmutableUtil](https://github.com/altjs/utils/blob/master/src/ImmutableUtil.js) makes working with immutable-js easy.\n* [TimeTravel](https://github.com/altjs/utils/blob/master/src/TimeTravel.js) enhances your stores so they are able to travel through different states in time.\n\n## Topical Guide\n\nFirst we install alt through npm. Although alt is also available through bower.\n\n```sh\nnpm install alt\n```\n\nThe following topical guide covers on using alt as a singleton in a traditional flux way.\n\nWe'll be referring back to this code a lot by using the `alt` reference declared.\n\n```js\nconst Alt = require('alt');\nconst alt = new Alt();\n```\n\n### ES6\n\nAlt is written in, and encourages ES6. It is completely optional but it is pleasant to write.\n\nYou can use the es6 transpiler that comes with react courtesy of\n[jstransform](https://github.com/facebookarchive/jstransform) or you can use one of the other popular ES6 transpilers:\n[babel](https://babeljs.io/) or [traceur](https://github.com/google/traceur-compiler).\n\nYou won't need an [es6-shim](https://github.com/paulmillr/es6-shim) but you can use one for further goodies in your javascripts.\n\nAlt does depend on ES5 features, the good news is so does React. You can use [es5-shim](https://github.com/es-shims/es5-shim)\nto support those pesky old browsers.\n\n##Typescript Definitions and Support\nThe 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](https://github.com/DefinitelyTyped/tsd). From here you can reference your typings as per usual with a reference tag ```\u003creference path=\"\u003cpath\u003e.d.ts\" /\u003e```. Check the [alt-typescript-tutorial](https://github.com/Shearerbeard/alt-typescript-tutorial) for more information and project examples.\n\nUsing Typescript 1.5 you can import with the legacy syntax:\n```\nimport Alt = require(\"alt\");\nimport chromeDebug = require(\"alt/utils/chromeDebug\");\nimport AltContainer = require(\"alt/AltContainer\");\n```\n\n### Creating Actions\n\nActions are the way you update state. They're kind of a big deal.\n\n`alt.createActions :: Class -\u003e Actions`\n\n```js\nclass LocationActions {\n  updateLocation(city) {\n    return city;\n  }\n}\n\nconst locationActions = alt.createActions(LocationActions);\n```\n\nYou 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:\n\n```js\nclass LocationActions {\n  updateLocationThatDoesItAsync(city) {\n    return (dispatch) =\u003e {\n      setTimeout(() =\u003e dispatch(city));\n    };\n  }\n}\n```\n\n`alt.createActions` then returns an `Object` containing all the methods defined. You can then call your actions directly.\n\n```js\nlocationActions.updateLocation('Paris');\n```\n\nWriting out actions that pass data through directly can get quite tedious so there's a shorthand for writing these what are essentially `identity` functions\n\n```js\nclass LocationActions {\n  constructor() {\n    // for single action\n    this.generateActions('updateLocation');\n\n    // as well as for many actions\n    this.generateActions('updateCity', 'updateCountry');\n  }\n}\n\nconst locationActions = alt.createActions(LocationActions);\n```\n\n```js\nlocationActions.updateLocation('Las Vegas')\n\nlocationActions.updateCity('Las Vegas')\nlocationActions.updateCountry('US')\n```\n\nRemember, `dispatch` only takes one argument. Therefore, if you need to pass multiple arguments into a store you can use an Object.\n\n```js\nclass LocationActions {\n  updateLocation(x, y) {\n    return { x, y };\n  }\n}\n\nconst locationActions = alt.createActions(LocationActions);\n\nlocationActions.updateLocation('Miami', 'Florida');\n```\n\nA shorthand function created in the constructor will pass through the multiple parameters as an Array\n\n```js\nclass LocationActions {\n  constructor() {\n    this.generateActions('updateLocation'); // ['South Lake Tahoe, 'California']\n  }\n}\n\nconst locationActions = alt.createActions(LocationActions);\n\nlocationActions.updateLocation('South Lake Tahoe', 'California');\n```\n\nThere's even a shorthand for the shorthand if all you're doing is generating a list of actions\n\n```js\nconst locationActions = alt.generateActions('updateLocation', 'updateCity', 'updateCountry');\n```\n\n### Stores\n\nStores are where you keep a part of your application's state.\n\nYou can either define your stores as a class/constructor-prototype or as an Object.\n\n`alt.createStore :: Class, string -\u003e Store`\n\n```js\nclass LocationStore {\n  constructor() {\n    this.bindAction(locationActions.updateLocation, this.onUpdateLocation);\n\n    this.state = {\n      city: 'Denver',\n      country: 'US'\n    };\n  }\n\n  onUpdateLocation(obj) {\n    const { city, country } = obj\n    this.setState({ city, country });\n  }\n}\n\nconst locationStore = alt.createStore(LocationStore);\n```\n\nYou can also use a regular old JavaScript Object to create your stores. This is more about aesthetic preference.\n\n```js\nconst locationStore = alt.createStore({\n  displayName: 'LocationStore',\n\n  bindListeners: {\n    onUpdateLocation: locationActions.updateLocation\n  },\n\n  state: {\n    city: 'Denver',\n    country: 'US'\n  },\n\n  onUpdateLocation(obj) {\n    const { city, country } = obj\n    this.setState({ city, country });\n  }\n});\n```\n\nIf 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.\n\n```js\nfunction LocationStore() {\n  this.city = 'San Francisco';\n  this.country = 'US';\n}\n\nLocationStore.prototype.onUpdateLocation = function (obj) {\n  this.city = obj.city;\n  this.country = obj.country;\n};\n```\n\nStore instances returned by `alt.createStore` can be listened to for updates by calling `listen`.\n\n`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.\n\n```js\nlocationStore.listen((data) =\u003e {\n  console.log(data)\n});\n```\n\nAlternatively, you can use the `unlisten` method. It takes in the same function you used for `listen` and unregisters it.\n\nAnother important method is `getState`, which returns a copy of the current store's state.\n\n```js\nlocationStore.getState().city === 'Denver'\n```\n\n#### Important Note\n\nAll 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\nObject via `alt.createStore`. This ensures that stores have no direct setters and the state remains mutable only through actions keeping the flow unidirectional.\nIf you want to attach public/static functions to your store the recommended method is to call the `exportPublicMethods` method from the constructor:\n\n```js\nclass LocationStore {\n  constructor() {\n    this.exportPublicMethods({\n      myPublicMethod: this.myPublicMethod\n    });\n  }\n\n  myPublicMethod() {\n    const internalInstanceState = this.getState();\n    return internalInstanceState;\n  }\n}\n\nconst locationStore = alt.createStore(LocationStore);\n\nlocationStore.myPublicMethod();\n```\n\nAn alternative is to declare the method as `static`, which will cause alt to expose the method on the store:\n\n```js\n// does the same thing as above except in a more magical way\nclass LocationStore {\n  static myPublicMethod() {\n    const internalInstanceState = this.getState();\n    return internalInstanceState;\n  }\n}\n```\n\n#### Canceling An Event\n\nIf you don't want the store to inform the view of an action you can call\n`this.preventDefault()` (or you can return false) from inside an action handler method.\n\n```js\nclass LocationStore {\n  constructor() {\n    this.bindAction(locationActions.updateCity, this.onUpdateCity);\n\n    this.state = {\n      city: 'Portland',\n      country: 'US'\n    };\n  }\n\n  onUpdateCity(city) {\n    this.setState({ city });\n\n    // ensure the view never finds out\n    this.preventDefault();\n  }\n}\n\nconst locationStore = alt.createStore(LocationStore);\n```\n\n#### Constants\n\nI thought you said there were no constants? Well, yeah, sort of. The thing is, they're automagically created for you.\nFeel free to use them to bind your actions or use the method itself, whatever reads better in your opinion.\n\n```js\nclass LocationStore {\n  constructor() {\n    this.bindAction(locationActions.UPDATE_CITY, this.onUpdateCity);\n\n    this.state = {\n      city: '',\n      country: ''\n    };\n  }\n}\n\nconst locationStore = alt.createStore(LocationStore);\n```\n\n#### Listening To Multiple Actions\n\n```js\nclass LocationActions {\n  constructor() {\n    this.generateActions('updateCity', 'updateCountry');\n  }\n}\n\nconst locationActions = alt.createActions(LocationActions);\n```\n\nUsing 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.\n\nThe function `bindListeners` is the inverse of `bindAction`. `bindListeners` takes an object of action handlers as keys and actions as a value.\n\n```js\nclass LocationStore {\n  constructor() {\n    this.bindListeners({\n      handleCity: locationActions.updateCity,\n      handleCountry: [locationActions.updateCountry, locationActions.updateLatLng]\n    });\n  }\n\n  handleCity(data) {\n    // will only be called by locationActions.updateCity()\n  }\n\n  handleCountry(data) {\n    // will be called by locationActions.updateCountry() and locationActions.updateLatLng()\n  }\n}\n```\n\nAlternatively, you can bind all the actions inside `locationActions` using the shortcut `bindActions`\n\n```js\nclass LocationStore {\n  constructor() {\n    this.bindActions(locationActions);\n\n    this.state = {\n      city: 'Austin',\n      country: 'US'\n    };\n  }\n\n  onUpdateCity(city) {\n    this.setState({ city });\n  }\n\n  onUpdateCountry(country) {\n    this.setState({ country });\n  }\n}\n\nconst locationStore = alt.createStore(LocationStore);\n```\n\nActions 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.\n\n#### Managing Store Data Dependencies\n\n`waitFor` is mostly an alias to Flux's Dispatcher waitFor. Here's an excerpt from the flux docs on what waitFor is designed for:\n\n\u003e 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.\n\nYou can use waitFor like so:\n\n```js\nconst dependingStore = alt.createStore(class DependingStore {\n  constructor() {\n    this.bindActions(someActions);\n\n    this.state = { answer: 42 };\n  }\n\n  onRandom(answer) {\n    this.setState({ answer });\n  }\n})\n\nconst locationStore = alt.createStore(class LocationStore {\n  constructor() {\n    this.bindActions(someOtherActions)\n\n    this.state = {\n      meaningOfLife: null\n    };\n  }\n\n  onThings() {\n    this.waitFor(dependingStore.dispatchToken);\n\n    this.setState({ meaningOfLife: dependingStore.getState().answer });\n  }\n})\n```\n\nYou can also `waitFor` multiple stores by passing in an Array: `this.waitFor([store1.dispatchToken, store2.dispatchToken])`\n\n### Views\n\nYour 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.\n\nIn this example I'll be using React, but you're free to use your library of choice.\n\n```js\n\nclass LocationView extends React.Component {\n  // these are methods that work with `connectToStores` which connects\n  // one or many stores to your component passing the state in as props.\n  // you're free to choose how the state from the store is passed into the\n  // component as props.\n\n  // this automatically does the listening/unlistening for you as well as\n  // handles the state changes\n  static getStores() {\n    return [locationStore];\n  }\n\n  static getPropsFromStores() {\n    return locationStore.getState();\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cp\u003e\n          City {this.props.city}\n        \u003c/p\u003e\n        \u003cp\u003e\n          Country {this.props.country}\n        \u003c/p\u003e\n      \u003c/div\u003e\n    )\n  }\n}\n\n// just make sure to wrap your component with connectToStores()\nexport default connectToStores(LocationView);\n```\n\n### Full Circle\n\nRestart the loop by making your views kick off new actions.\n\n## Alt Features\n\n### Snapshots\n\n`takeSnapshot :: ?...string -\u003e string`\n\nSnapshots 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\nserialized for persistence, transferring, logging, or debugging.\n\nTaking 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.\n\n### Bootstrapping\n\n`bootstrap :: string -\u003e undefined`\n\nBootstrapping 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)\nyou'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\non 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.\n\nBootstrap 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.\n\nIf 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.\n\n```js\nalt.createStore(LocationStore, 'LocationStore')\n```\n\n### Rollback\n\n`rollback :: undefined`\n\nIf 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\nthat 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.\n\n### Flushing\n\n`flush :: string`\n\nFlush 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.\n\n### Recycling\n\n`recycle :: ?...string -\u003e undefined`\n\nIf 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.\n\n### Lifecycle Methods\n\nWhen 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.\n\n`bootstrap` is called after the store has been bootstrapped. Here you can add some logic to take your bootstrapped data and manipulate it.\n\n```js\nclass Store {\n  constructor() {\n    this.on('bootstrap', () =\u003e {\n      // do something here\n    })\n  }\n}\n```\n\n`init` is called when the store is initialized as well as whenever a store is recycled.\n\n```js\nclass Store {\n  constructor() {\n    this.on('init', () =\u003e {\n      // do something here\n    })\n  }\n}\n```\n\n`rollback` is called whenever all the stores are rolled back.\n\n```js\nclass Store {\n  constructor() {\n    this.on('rollback', () =\u003e {\n      // do something here\n    })\n  }\n}\n```\n\n`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.\n\n```js\nclass Store {\n  constructor() {\n    this.on('error', (err, actionName, payloadData, currentState) =\u003e {\n      if (actionName === MyActions.fire) {\n        logError(err, payloadData);\n      }\n    });\n\n    this.bindListeners({\n      handleFire: MyActions.fire\n    });\n  }\n\n  handleFire() {\n    throw new Error('Something is broken');\n  }\n}\n```\n\n[See all the lifecycle methods](http://alt.js.org/docs/lifecycleListeners/)\n\n### Single Dispatcher\n\nA single dispatcher instance is made available for listening to all events passing through. You can access this via the `dispatcher` property: `alt.dispatcher`\nand listening to all events is as easy as\n\n```js\nalt.dispatcher.register(console.log.bind(console))\n```\n\nEach store has a reference to the dispatcher as well\n\n```js\nalt.createStore(class MyStore {\n  constructor() {\n    this.dispatcher.register(console.log.bind(console))\n  }\n})\n```\n\n### Flexibility\n\nYou 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.\nStores 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.\n\n### Server Side Rendering\n\nAlt was built with isomorphism in mind. This means that you can run full flux server-side and pick back up on the client-side.\n\nThere are two options for using flux on the server:\n\n* Keep stores as singletons, keep data loading synchronous, bootstrap, and flush.\n* Create multiple instances of flux and inject the context into your app.\n\n#### Stores as Singletons\n\nWith this approach your stores are singletons.\nAny 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\nthe store. Alternatively, you can gather all of your data, and once complete, you call `bootstrap()` which seeds all the stores with some initial data.\n\nOnce 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.\n\n#### Flux Instances\n\nCreating separate instances of flux rather than relying on singletons can help when building isomorphic applications.\n\nThe 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.\n\nSingletons only become a problem if you wish to share data fetching with client and server, don't want to use something like [Render](/src/utils/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.\n\nTaking 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](https://github.com/yahoo/fluxible) solves isomorphic applications.\n\nCreating a new alt instances is fairly simple.\n\n```js\nclass Flux extends Alt {\n  constructor() {\n    super();\n\n    this.addActions('myActions', ActionCreators);\n    this.addStore('storeName', Store);\n  }\n}\n\nconst flux = new Flux();\n```\n\n```js\n// client.js\n\nReact.render(\n  \u003cApp flux={flux} /\u003e,\n  document.body\n);\n```\n\n```js\n// server.js\nReact.renderToString(\u003cApp flux={flux} /\u003e);\n```\n\n```js\n// retrieving stores\nflux.getStore('storeName').getState();\n\n// actions\nflux.getActions('myActions');\n```\n\n#### Picking back up on the client\n\nTo help facilitate with isomorphism alt recommends you use [iso](https://github.com/goatslacker/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.\n\n## Converting a flux application to alt\n\n1. [Importing the chat project](https://github.com/goatslacker/alt/commit/1a54de1064fe5bd252979380e47b0409d1306773).\n2. [Adding alt and removing boilerplate](https://github.com/goatslacker/alt/commit/75ffdb53420dc32bdc2d99b5cf534cd0949331d8).\n3. [Converting some actions](https://github.com/goatslacker/alt/commit/6f8cf22ba6b36c6ae91a794fad75473c9436b683) and [the last action](https://github.com/goatslacker/alt/commit/58ea1418ecd2af25b578cd0f4b77c3d4d8631518).\n4. Converting the stores [MessageStore](https://github.com/goatslacker/alt/commit/f4c7bb4bb9027b53c380f98ed99a2e1b6ba5fa0b), [ThreadStore](https://github.com/goatslacker/alt/commit/bce2aadbb52981f934b4281b3a6244d4f2c4a7a9), and [UnreadThreadStore](https://github.com/goatslacker/alt/commit/0129baa5bd505ef26228e30cfa15a6ac4503a22d).\n5. [Finishing touches](https://github.com/goatslacker/alt/commit/e05a4e02f3f13831361136a21cd757416b69b4d8).\n\n## Differences Example\n\nFlux has constants, the dispatcher is also pretty dumb as in it just takes what you passed in the action\nand pipes it through to the store. This is completely fine but not something you should be expected to write.\nThe nice thing about constants is that you can easily grep for them in your application and see where\nall the actions are being called, with alt you get the same benefit without having to manage them.\n\n#### Before: Flux\n\n```js\nvar keyMirror = require('keymirror');\n\nvar actionConstants = keyMirror({\n  HANDLE_ACTION: null\n});\n\nvar action = {\n  foo() {\n    AppDispatcher.handleAction({ type: actionConstants.HANDLE_ACTION, data: 'foo' })\n  }\n};\n\nvar AppDispatcher = Object.assign(new Dispatcher(), {\n  handleAction(payload) {\n    this.dispatch(payload);\n  }\n});\n```\n\n#### After: Alt\n\n```js\nclass Action {\n  handleAction() {\n    return 'foo';\n  }\n}\n\nconst action = alt.createActions(Action);\n```\n\n## TL;DR\n\n* Isomorphic\n* Pure Flux\n* No constants\n* No static string checking\n* No giant switch statement\n* Save state snapshots\n* Rollbacks\n* Bootstrap components on app load\n* Light-weight and terse\n* ES6 Syntax, code your actions and stores with classes\n* Flexible\n* No direct setters on stores\n* Single dispatcher\n* Global listening for debugging\n* Small library\n\n## License\n\n[![MIT](https://img.shields.io/npm/l/alt.svg?style=flat)](http://josh.mit-license.org)\n","funding_links":[],"categories":["Uncategorized","Code Design","JavaScript","Client-side","List"],"sub_categories":["Uncategorized","Data Store"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoatslacker%2Falt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoatslacker%2Falt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoatslacker%2Falt/lists"}