From 33ca0c1915c3a6fefd4e643e9e4a8f30d46b5d5e Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Tue, 5 May 2015 10:51:22 -0700 Subject: [PATCH] An opinionated way of doing async with alt --- src/alt/utils/StoreMixins.js | 33 ++++++++++++++++++ src/alt/utils/StoreUtils.js | 4 +++ src/utils/decorators.js | 8 +++++ stargazer.js | 67 ++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 stargazer.js diff --git a/src/alt/utils/StoreMixins.js b/src/alt/utils/StoreMixins.js index ab52e6f0..e365de28 100644 --- a/src/alt/utils/StoreMixins.js +++ b/src/alt/utils/StoreMixins.js @@ -25,6 +25,39 @@ export const StoreMixinEssentials = { this.dispatcher.waitFor(tokens) }, + exportAsync(asyncMethods) { + const toExport = Object.keys(asyncMethods).reduce((publicMethods, methodName) => { + const asyncSpec = asyncMethods[methodName] + + const validHandlers = ['success', 'error', 'loading'] + validHandlers.forEach((handler) => { + if (asyncSpec[handler] && !asyncSpec[handler][ACTION_KEY]) { + throw new Error(`${handler} handler must be an action function`) + } + }) + + publicMethods[methodName] = (...args) => { + const state = this.getInstance().getState() + const value = asyncSpec.cache(state, ...args) + + // if we don't have it in cache then fetch it + if (!value) { + if (asyncSpec.loading) asyncSpec.loading() + asyncSpec.fetch(state, ...args) + .then(asyncSpec.success) + .catch(asyncSpec.error) + } else { + // otherwise emit the change now + this.emitChange() + } + } + + return publicMethods + }, {}) + + this.exportPublicMethods(toExport) + }, + exportPublicMethods(methods) { Object.keys(methods).forEach((methodName) => { if (typeof methods[methodName] !== 'function') { diff --git a/src/alt/utils/StoreUtils.js b/src/alt/utils/StoreUtils.js index c514635e..e9b6b6eb 100644 --- a/src/alt/utils/StoreUtils.js +++ b/src/alt/utils/StoreUtils.js @@ -135,6 +135,10 @@ export function createStoreFromClass(alt, StoreModel, key, ...argsForClass) { const store = new Store(...argsForClass) + if (config.datasource) { + StoreMixinEssentials.exportAsync.call(Store.prototype, config.datasource) + } + storeInstance = assign( new AltStore( alt, diff --git a/src/utils/decorators.js b/src/utils/decorators.js index 9e6345d1..2fa302f2 100644 --- a/src/utils/decorators.js +++ b/src/utils/decorators.js @@ -9,3 +9,11 @@ export function createStore(alt, ...args) { return alt.createStore(Store, undefined, ...args) } } + +export function datasource(source) { + return function (Store) { + Store.config = Store.config || {} + Store.config.datasource = source + return Store + } +} diff --git a/stargazer.js b/stargazer.js new file mode 100644 index 00000000..8e98a595 --- /dev/null +++ b/stargazer.js @@ -0,0 +1,67 @@ +import Alt from './' +import { createStore, datasource } from './utils/decorators' +import axios from 'axios' + +const alt = new Alt() + +const StargazerActions = alt.generateActions( + 'fetchingUsers', + 'usersReceived', + 'failed' +) + +const StargazerSource = { + fetchUsers: { + fetch(state) { + const url = `https://api.github.com/repos/${state.user}/${state.repo}/stargazers` + return axios({ url }).then(response => response.data) + }, + + cache(state) { + return state.users.length ? state.users : null + }, + + loading: StargazerActions.fetchingUsers, + + success: StargazerActions.usersReceived, + + error: StargazerActions.failed + } +} + +@createStore(alt) +@datasource(StargazerSource) +class StargazerStore { + constructor() { + this.user = 'goatslacker' + this.repo = 'alt' + this.users = [] + this.errorMessage = null + this.isLoading = false + + this.bindListeners({ + loading: StargazerActions.fetchingUsers, + receivedUsers: StargazerActions.usersReceived, + failed: StargazerActions.failed + }) + } + + loading() { + console.log('STORE: starting to load users') + this.isLoading = true + } + + failed(e) { + console.log('STORE: Uh oh') + this.errorMessage = e.statusText || String(e) + } + + receivedUsers(users) { + console.log('STORE: got users') + this.users = users + this.errorMessage = null + } +} + +StargazerStore.listen((state) => console.log('CHANGED', state.users.length)) +StargazerStore.fetchUsers()