Skip to content

Instantly share code, notes, and snippets.

@goatslacker
Last active September 1, 2015 00:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goatslacker/b3ea014881aa5b03488d to your computer and use it in GitHub Desktop.
Save goatslacker/b3ea014881aa5b03488d to your computer and use it in GitHub Desktop.
export default function fetch(store, source) {
const storeInst = store.getInstance ? store.getInstance() : store
const state = storeInst.getState()
const validHandlers = ['success', 'failure', 'begin', 'end']
validHandlers.forEach((handler) => {
if (source[handler] && !source[handler].id) {
throw new Error(`${handler} handler must be an action function`)
}
})
const value = source.local && source.local(state)
const shouldFetch = source.shouldFetch
? source.shouldFetch(state)
: value == null
if (shouldFetch) {
if (source.begin) source.begin()
const result = source.remote(state)
result.then(source.success, source.failure).then(source.end)
return result
} else {
return Promise.resolve(value)
}
}
// or you can just export the source and attach it wherever
import CompanyActions from '../actions/CompanyActions'
import { fetchCompanyUsingXhr } from '../request'
export default {
// required
local: state => state.company,
// optional
shouldFetch: state => !state.company || state.company._id !== state.companyId,
// required
remote: state => fetchCompanyUsingXhr(state.companyId),
// optional
begin: CompanyActions.fetchingCompany,
// required
success: CompanyActions.companyRetrieved,
// required
failure: CompanyActions.companyRequestFailed,
// optional
end: CompanyActions.fetchedCompany,
})
}
// using it in a store, you don't have to!
import alt from '../alt'
import CompanyActions from '../actions/CompanyActions'
import { fetchCompanyUsingXhr } from '../request'
import fetch from '../fetch'
class CompanyStore {
static displayName = 'CompanyStore'
constructor() {
this.exportPublicMethods({
fetchCompany: this::this.fetchCompany,
getCompanyId: this::this.getCompanyId,
})
this.bindActions(CompanyActions)
this.state = {
companyId: 1,
company: null,
}
}
companyRetrieved(company) {
this.setState({
company,
companyId: company._id,
})
}
getCompanyId() {
return this.state.companyId
}
fetchCompany() {
return fetch(this, {
// required
local: state => state.company,
// optional
shouldFetch: state => !state.company || state.company._id !== state.companyId,
// required
remote: state => fetchCompanyUsingXhr(state.companyId),
// optional
begin: CompanyActions.fetchingCompany,
// required
success: CompanyActions.companyRetrieved,
// required
failure: CompanyActions.companyRequestFailed,
// optional
end: CompanyActions.fetchedCompany,
})
}
}
export default alt.createStore(CompanyStore)
// you can use it as part of a util method
import fetch from '../fetch'
import CompanyStore from '../stores/CompanyStore'
import FetchCompanySource frmo '../sources/FetchCompanySource'
export const fetchCompany = () => fetch(CompanyStore, FetchCompanySource)
@goatslacker
Copy link
Author

@taion
Copy link

taion commented Aug 27, 2015

Is the biggest difference between this and the current Alt data source that it's more decoupled from the store itself? Pretty nice if so.

Two things that might be worth considering -

  • Assigning something like an ID to a fetch operation so that multiple "identical" concurrent fetches can be deduped
  • Some sort of unification of fetch with containers/&c. such that it's easy to use the fetch's return value for rendering a component (instead of separately specifying "fetch data" and "read data from store"... the resolved promise with the local value gets you most of the way there I guess)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment