Redux-Bundler Async Resources

2.0.1 · active · verified Tue Apr 21

This package provides bundle factories for `redux-bundler`, specializing in the management of asynchronous data resources. It offers `createAsyncResourceBundle` for handling single remote resources and `createAsyncResourcesBundle` for managing collections of async resources, each with its own lifecycle, including loading, staleness, and expiration. Key features include configurable `staleAfter` and `expireAfter` durations to manage data freshness and automatic removal, a `dependencyKey` mechanism for conditional fetching and automatic cache invalidation based on upstream selector changes, and support for `doAdjust` actions to optimistically update resource state after mutations. The current stable version is 2.0.1. Releases appear to be ad-hoc, driven by new features or bug fixes, rather than a strict time-based cadence. It differentiates itself by providing a more robust and opinionated approach to async resource management within the `redux-bundler` ecosystem, extending beyond `redux-bundler`'s native capabilities.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates how to define an async resource bundle for fetching and managing a single list of hot car deals, integrating it with a React component using `redux-bundler-hook`.

import { createSelector } from 'redux-bundler';
import { createAsyncResourceBundle } from 'redux-bundler-async-resources';
import React from 'react';
// Assume redux-bundler-hook is installed and configured for useConnect
import { useConnect } from 'redux-bundler-hook';

// Mock shopApi for demonstration purposes
const shopApi = {
  fetchHotCarDeals: () => {
    return new Promise(resolve => {
      setTimeout(() => {
        const deals = [{ id: 1, name: 'Sedan Deal', price: 25000 }, { id: 2, name: 'SUV Offer', price: 35000 }];
        console.log('Fetched hot car deals:', deals);
        resolve(deals);
      }, 1500); // Simulate network delay
    });
  }
};

// bundles/hotCarDeals.js
const hotCarDealsBundle = {
  ...createAsyncResourceBundle({
    name: 'hotCarDeals',
    staleAfter: 180000, // refresh every 3 minutes
    expireAfter: 60 * 60000, // delete if not refreshed in an hour
    getPromise: ({ shopApi: apiContext }) => apiContext.fetchHotCarDeals(),
  }),

  reactShouldFetchHotCarDeals: createSelector(
    'selectHotCarDealsIsPendingForFetch',
    shouldFetch => {
      if (shouldFetch) {
        return { actionCreator: 'doFetchHotCarDeals' };
      }
    }
  ),
};

// Component usage example (HotCarDeals.js)
const ErrorMessage = ({ error }) => <div style={{ color: 'red' }}>Error: {error?.message}</div>;
const Spinner = () => <div>Loading...</div>;
const CarDealsList = ({ deals }) => (
  <div>
    <h3>Hot Car Deals</h3>
    <ul>
      {deals.map(deal => (
        <li key={deal.id}>{deal.name}: ${deal.price}</li>
      ))}
    </ul>
  </div>
);

export default function HotCarDealsComponent() {
  // In a real app, 'shopApi' would be part of your main bundle's context
  const { hotCarDeals, hotCarDealsError } = useConnect(
      'selectHotCarDeals',
      'selectHotCarDealsError'
  );

  if (!hotCarDeals && hotCarDealsError) {
    return <ErrorMessage error={hotCarDealsError} />;
  }

  if (!hotCarDeals) {
    return <Spinner />;
  }

  return <CarDealsList deals={hotCarDeals} />;
}

// To run this:
// 1. Create a root bundler (e.g., composeBundles(hotCarDealsBundle, { getShopApi: () => shopApi }))
// 2. Wrap your app in <BundlerProvider bundler={store} />
// 3. Render <HotCarDealsComponent />

view raw JSON →