Accio
Declaratively fetch multiple APIs with a single React component.
Why Accio
Resolver as a plugin
There already exists a couple of declarative fetching libraries, but Accio is different as it allows you to use different resolver for each Accio call. You can think resolvers as plugins for performing different fetch mechanisms. The ultimate goal is to have a collection of reusable plugins that hide implementation details of integrating with 3rd party services such as Twitter or Facebook APIs.
// this example is just a concept and currently only has partial supportimport createTwitterResolver from 'accio-resolver-twitter';import createFacebookResolver from 'accio-resolver-facebook'; const TwitterResolver = const FacebookResolver = <Accio ="/my/tweets" => renderMyTweets</Accio> <Accio ="/my/facebook/posts" => renderMyFBPosts</Accio>
Accio as a standardized interface
Each 3rd party service has their own way to support integrations with our apps. Accio is an attempt to unify all of them in a simple API that helps React app developers build great user interfaces.
How to use
Setup
Using npm:
npm install --save react-accio
Using yarn:
yarn add react-accio
Importing Accio main component:
Basic example
<Accio ="https://www.google.com"> <div> accioPropsloading && <Spinner /> accioPropserror && <ErrorRenderer = /> accioPropsresponse && <GoogleComRenderer = /> </div> </Accio>
Specifying fetch options
Accio comes with a default window.fetch
resolver. You can pass the options such as method
or headers
as Accio props:
<Accio ="https://api.example.com/data" ="POST" = => renderAccio</Accio>
Deferring fetch
If you don't want Accio to start fetching immediately after render, use defer
& trigger
:
<Accio ="https://api.example.com/data" > <div> <Button = =>Click me to start fetching</Button> <App = /> </div> </Accio>
Using fetchKey prop
Use fetchKey prop if you want to re-trigger fetch based on your props.
This example will trigger fetch when prop url
change:
{ return propsurl;} <Accio ="https://api.example.com/data" => renderData</Accio>
Using render prop
Render prop exposes 4 properties: loading, error, response, and trigger*:
{ if error return <div>`Error! `</div> if loading return <Spinner /> if response return <DataTable = /> return null;} <Accio ="https://api.example.com/data"> renderData</Accio>
Handling errors
Error handling can be done by either rendering error component inside render prop OR specifying onError
callback prop:
<Accio ="https://api.example.com/data" => <ErrorHandler = /> </Accio>
Using lifecycle props
Lifecycle props provide an alternative way to react to fetch state changes. There are 4 currently supported lifecycle callbacks: onStartFetching
, onShowLoading
, onComplete
, and onError
:
<Accio ="https://api.example.com/data" = = = => renderData</Accio>
Delaying loading
Accio supports delaying loading so that your loading component will only be rendered after specified milliseconds. Use timeout
prop:
<Accio ="https://api.example.com/data" => renderData</Accio>
Caching responses
Accio can cache your responses if it detects at least two identical endpoints with the same request payload. But you have to make it explicit in order to do so:
import Accio AccioCacheProvider from 'react-accio' // on top of your app<AccioCacheProvider> <MyApp /></AccioCacheProvider> // inside your app<div> /* first fetch will hit the network & store to the nearest provider */ <Accio ="https://api.example.com/data">renderPageHeader</Accio> /* subsequent fetches will WAIT for the first resolver to complete fetching & storing to the cache */ /* only then it will read from the cache */ <Accio ="https://api.example.com/data">renderPageContent</Accio> /* use ignoreCache prop to skip cache reading & always fetch fresh data from network */ <Accio ="https://api.example.com/data" >renderPageFooter</Accio></div>
Preloading
You can preload deferred Accio calls ahead of time so that by the time you need the data, you will get it instantly.
Let's say you want to preload the cache whenever your users hover over your fetch trigger button:
import Accio AccioCacheProvider from 'react-accio' // Preloading only works when `AccioCacheProvider` is around.<AccioCacheProvider> <MyApp /></AccioCacheProvider> // Prepare a refconst resource = React; // Your app<Accio ="https://api.example.com/data" => trigger <button = = > Fetch </button> </Accio>
Complex fetching
Sometimes you want to do complex fetching mechanism such as polling. You cannot do that using render-prop without too many hacks. Thankfully, Accio provides an escape hatch for this use case where you can access its resolver anytime conveniently. That said, you can go back to imperative style coding by extracting Accio resolver:
const fetchAPI = Acciodefaultsresolver; { // start polling thispoller = ;}
Writing a resolver
When you buy a car, you get a working vehicle already assembled and preconfigured for you by the manufacturer. But sometimes you want more powers out of it, so instead of buying a new car (which would cost you another fortune) you can just replace the engine with a superior one, leaving the body, interior, and everything else the same. Accio works the same way, it allows you to replace the built-in resolver with a custom one that is more suitable to your use cases. Think of an Accio resolver as the engine in the car analogy, i.e., if you want more control over how you fetch data from the network (e.g., use axios
instead of window.fetch
) just write your own custom resolver.
Accio resolver has the following typedef:
type Resolver = url: string fetchOptions: Object context: Object Promise<any>;
Resolver arguments are given based on the following rules:
- url => Accio
url
prop - fetchOptions => any Accio prop that is not:
- 'children',
- 'url',
- 'context',
- 'defer',
- 'ignoreCache',
- 'onComplete',
- 'onError',
- 'onShowLoading',
- 'onStartFetching',
- 'timeout',
- '_cache'
- context => Accio
context
prop
Contributing
See CONTRIBUTING.md