(displayName: String, StoreModel: class): AltStore
Receives the Store model class and returns back the singleton instance for it. This method expects a class
that extends Store
, with methods that will be the action handlers. These action handlers will be invoked
by the dispatcher with the value returned by the action (or, in the case of Promises, the resolution or
error value) disclosed as two arguments:
Name | Type | description |
---|---|---|
value | object | Value returned from the Action |
action | Flux Standard Action | A Flux Standard Action corresponding to the Action method. It includes type , payload , error and meta attributes. type will be set to ${actionNameSpace}/${actionMethod} , which is the value used by ActionDispatcher to find the registered Store method listeners. |
Stores offer a different internal and external API to enforce that state is not exposed and changes follow the expected flow through Actions.
This is a reference to the internal name for this Store. It is the identifier provided to Alt#createStore()
.
getState(): object
Return the state of the store.
subscribe(listener: function): object
Registers a listener for changes in the state of this Store. This listener will be called after completion of any action handler
that does not call this.preventDefault()
. Returns an object with a single dispose()
method that can be used to stop listening
to lifecycle events.
// register for changes in state
const sub = MyStore.subscribe(this.onChange);
// stop listening
this.sub.dispose();
state: object
The state of this Store. Expected to be initialized in the constructor, and modified from action handlers using setState()
.
class LocationStore extends Alt.Store {
constructor() {
this.state = {
locations: []
}
}
onChangeLocations(locations) {
this.setState({ locations });
}
}
setState(state: object): undefined
setState
is used to set the state. You can override this method to provide your own setState implementation. Internally, setState will
create a shallow copy of the merged state, or replace entirely if the state is immutable (as returned by Object.isFrozen()
). setState()
will not trigger a change event; instead, a single event will be triggered once all action handlers are finished.
class MyStore {
handleFoo() {
this.setState({ foo: 0 });
}
}
preventDefault(): undefined
Called inside an action handler to indicate that a change event should not be triggered.
class MyStore() extends Alt.Store {
foo(value) {
if (this.state.value === value) {
// do not emit change event
this.preventDefault();
}
this.setState({ value });
}
}
(action: function, storeHandler: function): undefined
This method takes in an Action method and an action handler defined in your Store model class. The store method is then bound to that action so whenever the action dispatches a payload, the specified handler will receive it.
const MyActions = alt.generateActions('MyActions', [ 'foo', 'bar' ]);
class MyStore extends Alt.Store {
constructor() {
this.bindAction(MyActions.foo, this.handleFoo);
}
handleFoo(data) {
// do something with data
}
}
(actions: Actions): undefined
Takes in an Actions instance and binds all its methods to any action handlers in the Store model with the same name. A foo
action will match a foo
method in the Store.
const MyActions = alt.generateActions('MyActions', [ 'foo', 'bar' ]);
class MyStore extends Alt.Store {
constructor() {
this.bindActions(MyActions);
}
foo(data) {
// do something with data
}
bar(data) {
// same here
}
}
You can define an otherwise
method in your action to receive any dispatched values not explicitely managed by the Store class.
const MyActions = alt.generateActions('MyActions', [ 'foo', 'bar', 'baz' ]);
class MyStore extends Alt.Store {
constructor() {
this.bindActions(MyActions);
}
foo(data) {
// handle MyActions.foo()
}
otherwise(values) {
// handle MyActions.bar() and MyActions.baz()
}
}
(listenersMap: object): undefined
bindListeners
is the inversion of bindAction
. Accepts an object where the keys correspond to the method names in the
Store model and the values are either an array of actions or a single one.
import MyActions from '../actions/MyActions';
import OtherActions from '../actions/OtherActions';
class MyStore extends Alt.Store {
constructor() {
this.bindListeners({
handleFoo: MyActions.foo,
handleBar: [MyActions.bar, OtherActions.bar]
});
}
handleFoo(data) {
// will only be called by MyActions.foo()
}
handleBar(data) {
// will be called by MyActions.bar() and OtherActions.bar()
}
}
emitChange(value: Object = this.state)
Will emit a change
event to all observers that have been registered by Store.subscribe()
. If value
is missing, this.state
will be used.
class MyStore extends Store {
constructor() {
super();
this.state = {
foo: 1,
bar: 2
};
}
inc(key) {
const partValue = {};
partValue[key] = (this.state[key] || 0) + 1;
this.setState(partValue);
// do not emit everything, just the modified value
this.preventDefault();
this.emitChange(partValue);
}
};
Stores are plain EcmaScript classes that can initialize state in the constructor. For example, you application could include some state in the HTML page:
<script type="application/json" id="currentUser">
{ "id": 42, "name": "John Doe", "enabled": true }
</script>
<script src="MyApp"></script>
Then the application can use this state to initialize the Store:
UserStore.js
import Store from 'alt-ng/Store';
class UserStore extends Store {
constructor(currentUser) {
this.state = { currentUser };
}
}
export default function(alt, currentUser) {
return alt.createStore('UserStore', new UserStore(currentUser));
}
MyApp.js
import createUserStore from '../stores/UserStore';
import alt from './alt';
const currentUser = JSON.parse(document.getElementById('currentUser').html());
const store = createUserStore(alt, currentUser);
You can also get creative by processing and saving parts of the state to localStorage
:
// save state
const { currentUser } = store.getState();
localStorage.setItem('currentUser', JSON.stringify(currentUser));
// restore state
const restoredUser = JSON.parse(localStorage.getItem('currentUser'));
store = createUserStore(alt, restoredUser);