# Async Data Fetching Consider it a given that this talks to a RESTful API (simple crud and, in my case, predicate filtering). There is a `FetchStore` that manages the API calls, ensuring there aren't duplicate calls, resolving promises once data arrives, etc. The store itself is rather opaque. It doesn't have any public accessors. The `FetchActions` defines two actions for clients to call, and two for other stores to consume in the dispatch cycle: ```javascript import alt from './alt' class FetchActions { constructor() { this.generateActions( // Stores listen for this, payload contains resource type, // query, and response data. 'resourceFetched', // Same, except contains error information 'resourceFetchFailure' ) } // A 'fire and forget' method used by other stores. Just // signals that data needs to be fetched for this type // and query (usually an id). loadResource( type, query) { this.dispatch({ type, query }) } // Primarily used in resolving data pre-route rendering, // this returns a Promise that resolves once the resource(s) // have been loaded and processed through the dispatcher. retrieveResource( type, query) { return new Promise(( resolve, reject) => { function callback( err, data) { if( err) reject( err) else resolve( data) } this.dispatch({ type, query, callback }) }) } } export default alt.createActions( FetchActions) ``` That's basically it. Internally, the `FetchStore` keeps track of pending requests, and any associated callbacks, resolving them once the `xhr` returns. Here's an example of how it's used by other Stores: ```javascript import alt from './alt' import CompanyActions from './CompanyActions' import FetchActions from './FetchActions' const COMPANY_TYPE= "Company" class CompanyStore { constructor() { this.bindActions( CompanyActions) this.bindActions( FetchActions) this.idmap= {} } onResourceFetched({ type, query, data }) { if( type === COMPANY_TYPE) { this.idmap[ data.companyId]= data } else { return false } } static get( id) { const company= this.getState().idmap[ id] if( Type.isUndefined( company)) { FetchActions.loadResource( COMPANY_TYPE, id) } return company } } export default alt.createStore( CompanyStore, 'CompanyStore') ``` In the application, I treat `undefined` and `null` differently. If a value is `undefined` it's unfetched data, if `null` then it's been fetched with no results --- Just for completeness, here's my implementation my `FetchStore`. It's not plug-n-play because I have a class (`Resource`) that wraps the CRUD url generation and xhr calling. But it'd be easy to hook up with raw xhr calls. ```javascript import alt from './alt' import FetchActions from './FetchActions' import {Resource} from 'toolkit' class FetchStore { constructor() { this.bindActions( FetchActions) this.queue= {} } onLoadResource({ type, query }) { this._loadResource( type, query) } onRetrieveResource({ type, query, callback }) { this._loadResource( type, query, callback) } _loadResource( type, query, callback) { const token= this._tokenize( type, query), enqueued= this.queue[ token], api= Resource.type( type) if( enqueued ) { // Request already sent... if( callback) { // Add this callback to the other queued callbacks enqueued.callbacks.push( callback) } return } this.queue[ token]= defaultState() const apiCall= (Type.isObject( query) ? api.find( query) : api.get( query)) .then( this._resourceResponse.bind( this, type, query, token, true)) .catch( this._resourceResponse.bind( this, type, query, token, false)) } _resourceResponse( type, query, token, success, data) { const info= this.queue[ token] if( success) { FetchActions.resourceFetched({ type, query, token, data}) } else { FetchActions.resourcenUnfetched({ type, query, token, data}) } info.callbacks .forEach( callback => { if( success) callback( null, data) else callback( data) }) delete this.queue[ token] } _tokenize( type, query) { return JSON.stringify({ type, query}) } } export default alt.createStore( FetchStore, 'FetchStore') function defaultState() { return { callbacks: [], error: null, finish: null, start: new Date() } } ```