redux-repository

0.6.3 • Public • Published

redux-repository

npm CI CD Coverage Status

A versatile set of pure functions to simplify the management of remote resources with Redux.

  • A single resource consists of:
    • ID
    • status: requested, received, failed
    • data, if the status is received
    • error, if the status is failed
    • timestamp of the data or error acquisition
  • The same resource can be requested from multiple places at the same time, it will only be fetched once
  • Resources are stored in the normalized state shape
  • Resources can be cached to skip consequent fetching
  • Read-only operations are supported so far: fetch and reset (remove local copy)

Quick Start

Install

npm install redux-repository

Use

Implement action creators first:

import { createFetchResource, createResetResources } from 'redux-repository/lib/actions';
import { Action } from 'redux-repository/lib/types';
import { ThunkAction } from 'redux-thunk';

import { Product } from './Product';
import { State } from './State';

export interface FetchProductAction {
  (id: string): void;
}

export interface ResetProductsAction {
  (): void;
}

export const fetchProduct = (id: string): ThunkAction<void, State, null, Action<Product, string>> => (
  createFetchResource(
    'product',
    id,
    ({ catalog: { products } }) => products,
    (dispatchReceived, dispatchFailed) => {
      fetch(`https://example.com/api/products/${id}`)
        .then(response => response.json())
        .then(data => dispatchReceived(data))
        .catch(error => dispatchFailed(error.toString()));
    },
    {
      silentAlready: true, // skip "already received" messages, optional
      ttl: 60 * 1000, // cache for 1 minute, optional
    },
  )
);

export const resetProducts = (): ThunkAction<void, State, null, Action<Product, string>> => (
  createResetResources('product')
);

Then, inject the repository reducer:

import { Action } from 'redux';
import { isResourceAction, repositoryReducer } from 'redux-repository/lib/reducer';
import { createInitialState } from 'redux-repository/lib/repository';
import { Action as ReduxRepositoryAction } from 'redux-repository/lib/types';

import { Product } from './Product';
import { State } from './State';

const initialState: State = {
  // ...
  catalog: {
    // ...
    products: createInitialState(),
  },
};

export default (state: State = initialState, action: Action): State => {
  if (isResourceAction('product', action as ReduxRepositoryAction<Product, string>)) {
    return {
      ...state,
      catalog: {
        ...state.catalog,
        products: repositoryReducer(state.catalog.products, action as ReduxRepositoryAction<Product, string>),
      },
    };
  }

  switch (action.type) {
    // ...
    default:
      return state;
  }
};

That's it! Now you can trigger fetchProduct, resetProducts and wire components to the repository via state:

import { connect } from 'react-redux';
import { Repository } from 'redux-repository/lib/interfaces';

import { fetchProduct, FetchProductAction } from './actions';
import { Product } from './Product';
import { State } from './State';

interface StateProps {
  products: Repository<Product, string>;
}

interface DispatchProps {
  fetchProduct: FetchProductAction;
}

const mapStateToProps = ({ catalog: { products } }: State): StateProps => ({ products });
const mapDispatchToProps: DispatchProps = { fetchProduct };

export const connect = connect(mapStateToProps, mapDispatchToProps);

The full list of exported entities that might be useful:

import {
  createFetchResource,
  createResetResources,
} from 'redux-repository/lib/actions';

import {
  RequestedResource,
  ReceivedResource,
  FailedResource,
  Resource,
  Repository,
} from 'redux-repository/lib/interfaces';

import {
  isResourceAction,
  repositoryReducer,
} from 'redux-repository/lib/reducer';

import {
  createInitialState,
  getResourceById,
  getResourcesArrayByIds,
  pushResource,
  pushResourcesArray,
  mergeRepositories,
} from 'redux-repository/lib/repository';

import {
  createFailed,
  createReceived,
  createRequested,
  extractData,
  extractError,
  isExpired,
  isFailed,
  isReceived,
  isRequested,
} from 'redux-repository/lib/resource';

import {
  Action,
} from 'redux-repository/lib/types';

// Examples:
const productResource = getResourceById(productsRepository, productId);
const productData = extractData(productResource);
const productProgress = isRequested(productResource);

/redux-repository/

    Package Sidebar

    Install

    npm i redux-repository

    Weekly Downloads

    2

    Version

    0.6.3

    License

    MIT

    Unpacked Size

    40.2 kB

    Total Files

    20

    Last publish

    Collaborators

    • loginov-rocks