Skip to content
High-Level Resource Manager for Flux Architecure
TypeScript JavaScript
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode
packages
.gitignore
LICENSE
README.md

README.md

@async-resource

Motivation

When writing flux-like http stores it's common to repeat lots of boilerplate code to handle loading, error, caching, parallel requisitions, etc. This project's objective is to provide a common language on how http flow behaves across an app, plus some very useful functionality, like:

  • Caching
  • TTL
  • Retrying (not implemented yet)
  • Isolation, testability, mocking

Works with: redux, vuex, react+redux

Usage

import {
  createStore,
  combineReducers,
} from 'redux'
import {
  applyResourceToStore,
  reducers,
  registerResource,
} from '@async-resource/redux'

// -> register your api
registerResource('user', {
  source: () => axios.get('/rest/user-info'),
})
// -> setup an store with your resources
export const store = createStore(combineReducers(reducers))
// -> register store as a resource consumer
applyResourceToStore(store)


// ...

import {
  Resource,
  withResource,
} from '@async-resource/react-redux'

// Use Render Props
const UserInfo = () => (
  <Resource id="user" render={(resource) => {
      if (resource.loading) return <div> Loading </div>
      if (resource.loaded) return <div> Data: { resource.data.name } </div>
      throw new Error('should not get here')
    }}
  />
)

// OR use a HOC
const UserInfo = withResource('error', {
  Loading: () => <div>Loading</div>,
  Loaded: ({ data: { name } }) => <div>{ name }</div>,
  Error: ({ error }) => <div>{ error }</div>,
})

// Or connect with redux yourself :)

How it works

The idea is to work in any environment, so the logic is divided in 4 packages

Core

Always necessary

npm install --save @async-resource/core

import {
  registerResource,
  subscribe,
} from '@async-resource/core'

// -> Register resource
registerResource('user', {
  source: () => axios.get('/rest/user-info'),
  cache: { TTL: 24 * 60 * 60 * 1000 } // caches for a day
})

// -> listen for resource change
subscribe('user', resource => {
  // readonly cache: boolean
  // readonly loading: boolean
  // readonly loaded: boolean
  // readonly error: string | null
  // readonly data: any
})

// ...

// -> call resource
resources.consume('user')

Redux

npm install --save @async-resource/redux

import connectResource, {
  consumeAction,
  reducers,
  registerResource,
  applyResourceToStore,
} from '@async-resource/redux'

// use it with https://github.com/ioof-holdings/redux-dynamic-reducer
// to add reducers dynamically
export const store = createStore(combineReducers({}))
const { registerResource: registerDynamicResource } = connectResource(store)
registerResource('user', {
  source: () => axios.get('/rest/user-info'),
})


// or use with a constant store
registerResource('user', {
  source: () => axios.get('/rest/user-info'),
})
export const store = createStore(combineReducers(reducers))
applyResourceToStore(store)


// interact with redux
store.dispatch(consumeAction('user'))

Vuex

npm install --save @async-resource/vuex

import connectResource from '@async-resource/vuex'

// create store
const store = new Store({})
const { registerResource } = connectResource(store)

// register resources dynamically
registerResource('user', {
  source: () => axios.get('/rest/user-info'),
})

// interact with vuex
await store.dispatch('userResource/consume')

React-Redux (works with React-Native)

npm install --save @async-resource/react-redux

import {
  Resource,
  withResource,
} from '@async-resource/react-redux'

// Use Render Props
const UserInfo = () => (
  <Resource id="user" render={(resource) => {
      if (resource.loading) return <div> Loading </div>
      if (resource.loaded) return <div> Data: { resource.data.name } </div>
      throw new Error('should not get here')
    }}
  />
)

// OR use a HOC
const UserInfo = withResource('error', {
  Loading: () => <div>Loading</div>,
  Loaded: ({ data: { name } }) => <div>{ name }</div>,
  Error: ({ error }) => <div>{ error }</div>,
})

TODOs

  • Retrying
  • Pagination
  • Vue Component with JSX: HOC and Render Props
  • Separate documentation for packages
  • Better documentation
  • Unify packages versions
You can’t perform that action at this time.