Skip to content

Instantly share code, notes, and snippets.

@honzabrecka
Last active October 27, 2017 06:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save honzabrecka/3b584f70ad3810f57f08c3bc8fbf6cbe to your computer and use it in GitHub Desktop.
Save honzabrecka/3b584f70ad3810f57f08c3bc8fbf6cbe to your computer and use it in GitHub Desktop.
const effects = {}
const coeffects = {}
const actions = {}
const state = {}
function registerEffect(id, f) {
effects[id] = f
}
function registerCoeffect(id, f) {
coeffects[id] = f
}
function registerAction(id, f) {
actions[id] = f
}
function dispatch(action) {
const handled = actions[action[0]]({ ...coeffects, state }, action)
// update state
state = handled.state ? { ...state, ...handled.state } : state
// run effects
Object.keys(handled)
.filter((id) => id !== 'state')
.filter((id) => !!effects[id])
.forEach((id) => {
effects[id]({ ...effects, dispatch }, handled[id])
})
}
/////
registerCoeffect('localStorage', (key) => {
return window.localStorage(key)
})
registerEffect('localStorage', (_, [key, value]) => {
window.localStorage(key, value)
})
registerCoeffect('uuid', uuid)
registerEffect('fetch', async ({ dispatch }, req) => {
try {
const res = await window.fetch(req)
dispatch([...req.onSuccess, res])
} catch (e) {
dispatch([...req.onError || ['GLOBAL_ERROR'], e])
}
})
registerEffect('fetchBatch', async (effects, batch) => {
const { fetch, dispatch } = effects
await Promise.all(batch.map((req) => fetch(effects, req)))
dispatch(['BATCH_DONE'])
})
registerAction('LOGIN', (_, [, credentials]) => ({
fetch: {
url: '/login',
method: 'post',
onSuccess: ['LOGIN_SUCCESS']
}
}))
registerAction('LOGIN_SUCCESS', (_, [, { token }]) => ({
localStorage: ['token', token]
}))
registerAction('PROFILE', ({ state, localStorage, uuid }, [, id]) => {
const fetch = {
url: '/profile/' + id,
headers: { authorization: localStorage('token') },
onSuccess: ['PROFILE_SUCCESS', id, uuid],
onError: ['PROFILE_ERROR', id, uuid],
id: uuid()
}
return {
fetch,
state: {
pendingQueue: [...state.pendingQueue, fetch]
}
}
})
registerAction('PROFILE_SUCCESS', ({ state }, [, , uuid, data]) => ({
state: {
profile: data,
pendingQueue: state.pendingQueue.filter(({ id }) => id !== uuid)
}
}))
registerAction('PROFILE_ERROR', (_, [, , uuid, error]) => {
if (error.res.status === 401) {
return {
fetch: {
url: '/token',
onSuccess: ['TOKEN_SUCCESS']
},
state: {
pendingQueue: state.pendingQueue.filter(({ id }) => id !== uuid),
waitingQueue: [...state.waitingQueue, state.pendingQueue.filter(({ id }) => id === uuid)[0]]
}
}
}
return { state: { globalError: error.message } }
})
registerAction('TOKEN_SUCCESS', ({ state }, [, { token }]) => ({
localStorage: ['token', token],
fetchBatch: [...state.waitingQueue, ...state.pendingQueue]
}))
registerAction('GLOBAL_ERROR', ({ state }, [, error]) => ({
state: { globalError: error.message }
}))
dispatch(['LOGIN'])
dispatch(['PROFILE', 7654])
dispatch(['PROFILE', 7897])
dispatch(['PROFILE', 2345])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment