SkillAgentSearch skills...

Resourcerer

Declarative data-fetching and caching framework for REST APIs with React

Install / Use

/learn @noahgrant/Resourcerer
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<img src="https://user-images.githubusercontent.com/1355779/61337603-f9fffd80-a7ea-11e9-9cb3-fa82e044c86e.png" alt="Resourcerer Icon" height="200" width="200" />

resourcerer

resourcerer is a library for declaratively fetching and caching your application's data. Its powerful useResources React hook or 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
  • < 6kB!

Getting started is easy:

  1. Define a model in your application (these are classes descending from Model or Collection):
// js/models/todos-collection.js
import {Collection} from 'resourcerer';

export default class TodosCollection extends Collection {
  url() {
    return '/todos';
  }
}
  1. Create a config file in your application and add your constructor to the ModelMap with a key:
// 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});
// in your top level js file
import 'js/core/resourcerer-config';
  1. Use your preferred abstraction (useResources hook or withResources HOC) to request your models in any component:

    1. useResources

      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 (
          <div className='MyComponent'>
            {isLoading ? <Loader /> : null}
      
            {hasErrored ? <ErrorMessage /> : null}
      
            {hasLoaded ? (
              <ul>
                {todosCollection.toJSON().map(({id, name}) => (
                  <li key={id}>{name}</li>
                ))}
              </ul>
            ) : null}
          </div>
        );
      }
      
    2. withResources

      import React from 'react';
      import {withResources} from 'resourcerer';
      
      // tell resourcerer which resource you want to fetch in your component
      @withResources((props) => ({todos: {}}))
      class MyComponent extends React.Component {
        render() {
          // when MyComponent is mounted, the todosCollection is fetched and available
          // as `this.props.todosCollection`!
          return (
            <div className='MyComponent'>
              {this.props.isLoading ? <Loader /> : null}
      
              {this.props.hasErrored ? <ErrorMessage /> : null}
      
              {this.props.hasLoaded ? (
                <ul>
                  {this.props.todosCollection.map((todoModel) => (
                    <li key={todoModel.id}>{todoModel.get('name')}</li>
                  ))}
                </ul>
              ) : null}
            </div>
          );
        }
      }
      

There's a lot there, so let's unpack that a bit. There's also a lot more that we can do there, so let's also get into that. But first, some logistics:

Contents

  1. Installation
  2. Nomenclature
  3. Tutorial
    1. Intro
    2. Other Props Returned from the Hook/Passed from the HOC (Loading States)
    3. Requesting Prop-driven Data
    4. Changing Props
    5. Common Resource Config Options
      1. params
      2. options
      3. noncritical
      4. force
      5. Custom Resource Names
      6. prefetches
      7. data
      8. lazy
      9. minDuration
      10. dependsOn
      11. provides
    6. Data mutations
    7. Serial Requests
    8. Canonical Models
    9. Differences between useResources and withResources
    10. Using resourcerer with TypeScript
    11. Caching Resources with ModelCache
    12. Declarative Cache Keys
    13. Prefetch on Hover
    14. Refetching
    15. Cache Invalidation
    16. Tracking Request Times
  4. Configuring resourcerer
  5. FAQs
  6. Migrating to v2.0

Installation

$ npm i resourcerer or yarn add resourcerer

resourcerer requires on React >= 16.8 but has no external dependencies.

Note: Resourcerer is written in TypeScript and is compiled to ESNext. It does no further transpiling—including import/export. If you are using TypeScript yourself, this won't be a problem. If you're not, and you're not babelifying (or similar) your node_modules folder, you'll need to make an exception for this package, ie:

// webpack.config.js or similar
module: {
  rules: [{
    test: /\.jsx?$/,
    exclude: /node_modules\/(?!(resourcerer))/,
    use: {loader: 'babel-loader?cacheDirectory=true'}
  }]
}

Nomenclature

  1. Props. Going forward in this tutorial, we'll try to describe behavior of both the useResources hook and the withResources HOC at once; we'll also rotate between the two in examples. Note that if we talking about a passed prop of, for example isLoading, that that corresponds to an isLoading property returned from the hook and a this.props.isLoading prop passed down from the HOC.

  2. ResourceKeys. These are the keys of the object passed to the register function in your top-level resourcerer-config.js file (discussed above in the introduction). The object is of type Record<ResourceKeys, new () => Model | new () => Collection>. These keys are passed to the executor functions and are used to tell the hook or HOC which resources to request.

  3. Executor Function. The executor function is a function that both the hook and HOC accept that declaratively describes which resources to request and with what config options. In these docs you'll often see it assigned to a variable called getResources. It accepts props as arguments and may look like, as we'll explore in an example later:

    const getResources = (props) => ({user: {path: {userId: props.id}}});
    

    or

    const getResources = (props) => {
      const now = Date.now();
      
      return {
        userTodos: {
          params: {
            limit: 20,
            end_time: now,
            start_time: now - props.timeRange,
            sort_field: props.sortField
          }
        }
      };
    };
    

    It returns an object whose keys represent the resources to fetch and whose values are Resource Configuration Objects that we'll discuss later (and is highlighted below).

  4. Resource Configuration Object. In the object returned by our executor function, each entry has a key equal to one of the ResourceKeys and whose value we will refer to in this document as a Resource Configuration Object, or Resource Config for short. It holds the declarative instructions that useResources and withResources will use to request the resource.

Tutorial

Okay, back to the initial example. Let's take a look at our useResources usage in the component:

// `@withResources((props) => ({todos: {}}))`
const getResources = (props) => ({todos: {}});

export default function MyComponent(props) {
  const resources = useResources(getResources, props);
  
  // ...
}

You see that useResources takes an executor function that returns an object. The executor function takes a single argument: the current props, which are component props when you use withResources, but can be anything when you use useResources. The executor function returns an object whose keys are ResourceKeys and whose values are Resource Config objects. Where do ResourceKeys come from? From the object passed to the register method in the config file we added earlier!

// js/core/resourcerer-config.js
import {register} from 'resourcerer';
import TodosCollection from 'js/models/todos-collection';

// after adding this key, `todos` can be used in our executor functions to reference the Todos resource.
// The 'todos' string value will also be the default prefix for all todos-related return values.
// That's why we have `props.todosCollection`!
register({todos: TodosCollection});

(We can also pass custom prefixes for our prop names in a component, but we'll get to that later.)

Back to the executor function. In the example above, you see it returns an object of {todos: {}}. In general, the object it should return is of type `{[key: ResourceKe

View on GitHub
GitHub Stars82
CategoryDevelopment
Updated19d ago
Forks4

Languages

JavaScript

Security Score

100/100

Audited on Mar 12, 2026

No findings