# resourcerer
`resourcerer` is a library for declaratively fetching and caching your application's data. Its powerful [`useResources`](#useresources) React hook or [`withResources`](#withresources) higher-order React component (HOC) allows you to easily construct a component's data flow, including:
* serial requests
* prioritized rendering for critical data (enabling less critical or slower requests to not block interactivity)
* delayed requests
* prefetching
* inter-model syncing
* ...and more
Additional features include:
* fully declarative (no more writing any imperative Fetch API calls)
* first-class loading and error state support
* smart client-side caching
* lazy fetching
* refetching
* forced cache invalidation
* updating a component when a resource updates
* zero dependencies
* under 10kB gzipped!
Getting started is easy:
1. Define a model in your application (these are classes descending from [Model](/docs/model.md) or [Collection](/docs/collection.md)):
```js
// js/models/todos-collection.js
import {Collection} from 'resourcerer';
export default class TodosCollection extends Collection {
url() {
return '/todos';
}
}
```
2. Create a config file in your application and add your constructor to the ModelMap with a key:
```js
// js/core/resourcerer-config.js
import {register} from 'resourcerer';
import TodosCollection from 'js/models/todos-collection';
// choose any string as its key, which becomes its ResourceKey
register({todos: TodosCollection});
```
```js
// in your top level js file
import 'js/core/resourcerer-config';
```
3. Use your preferred abstraction (`useResources` hook or `withResources` HOC) to request your models in any component:
1. ### useResources
```jsx
import {useResources} from 'resourcerer';
// tell resourcerer which resource you want to fetch in your component
const getResources = (props) => ({todos: {}});
function MyComponent(props) {
const {
isLoading,
hasErrored,
hasLoaded,
todosCollection
} = useResources(getResources, props);
// when MyComponent is mounted, the todosCollection is fetched and available
// as `todosCollection`!
return (
Todo not found.
; } return ( // ... ); } ``` Each one of these methods exhibit the following behaviors: 1. They automatically fire off the appropriate request with the right data and at the right url 1. They will cause every component registered to that resource to re-render with the updated data, keeping the application in sync 1. On error, they undo the changes that were done (and their registered components render again). **Note:** 1. All calls resolve an array, which is a tuple of `[model, response]`. All reject with just the response. 1. All write calls must have a `.catch` attached, even if the rejection is swallowed. Omitting one risks an uncaught Promise rejection exception if the request fails. ## Serial Requests In most situations, all resource requests should be parallelized; but that’s not always possible. Every so often, there may be a situation where one request depends on the result of another. For these cases, we have the `dependsOn` resource config option and the `provides` resource config option. These are probably best explained by example, so here is a simplified instance from the [Sift](https://sift.com) Console, where we load a queue item that has info about a user, but we can't get further user information until we know what user id belongs to this queue item. ```js @withResources((props) => ({ user: { path: {userId: props.userId}, dependsOn: !!props.userId }, queueItem: { data: {id: props.itemId}, provides: (queueItemModel) => ({userId: queueItemModel.get('userId')}) } })) export default class QueueItemPage extends React.Component {} In this simplified example, only `props.itemId` is initially present at the url `items/An error occurred.