npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-async-adapter

v1.14.0

Published

A simple redux toolkit adapter to handle loading states for async thunks. Inspired by Redux Toolkit's `createEntityAdapter` and is designed to work with Redux Toolkit's `createAsyncThunk`.

Downloads

9

Readme

Redux Async Adapter

A simple redux toolkit adapter to handle loading states for async thunks. Inspired by Redux Toolkit's createEntityAdapter and is designed to work with Redux Toolkit's createAsyncThunk.

Overview

A function that generates a set of reducers and selectors for keeping track of loading state (loading, loaded, error, lastLoaded) for different async operations. It supports multiple loading statuses within a state.

The methods generated by createAsyncAdapter will all manipulate an "async state" structure that looks like:

import { SerializedError } from '@reduxjs/toolkit';

export interface AsyncState<T> {
  status: { [name: string]: AsyncStatus | undefined };
  data: T;
}

export interface AsyncStatus {
  name: string;
  loading: boolean;
  loaded: boolean;
  error: SerializedError | undefined;
  lastLoaded: string | undefined;
}

createAsyncAdapter can be called multiple times within an application and can handle async thunks created by createAsyncThunk

Example

import createAsyncAdapter from 'redux-async-adapter'
import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit'

// create the adapter
const asyncAdapter = createAsyncAdapter()

// create an async thunk that load books
const fetchBooks = createAsyncThunk(
  'books/fetch',
  async () => {
    // fetch books from some api
    return ['book 1', 'book 2']
  }
)

const booksSlice = createSlice({
  name: 'books',
  initialState: asyncAdapter.getInitialState([])
  reducers: {},
  extraReducers: {
    // use the handler directly
    [fetchBooks.pending.type]: asyncAdapter.handlePending(fetchBooks),

    // use the handler as part of a reducer
    [fetchBooks.fulfilled.type]: (state, action) => {
      asyncAdapter.handleFulfilled(fetchBooks)(state)
      state = action.payload
    },

    [fetchBooks.rejected.type]: asyncAdapter.handleRejected(fetchBooks),
  }
})

const store = configureStore({
  reducer: {
    books: booksSlice.reducer
  }
})

// use the selectors to get the thunk's status
const fetchBooksStatus =
  asyncAdapter
    .getSelectors()
    .selectAsyncStatus(store.getState(), fetchBooks)

// access various statuses
const {loading, error, loaded, lastLoaded} = fetchBooksStatus

Parameters

createAsyncAdapter accepts an optional options parameter which an an object containing the configuration for the adapter.

Options

  • usePayloadAsError boolean?: use the payload field of a rejected action instead of the error field. This is useful if you are using rejectWithValue in your async thunk
  • onFulfilled function?: a function that receives an AsyncStatus and returns an AsyncStatus that is run after handleFulfilled
  • onPending function?: a function that receives an AsyncStatus and returns an AsyncStatus that is run after handlePending
  • onRejected function?: a function that receives an AsyncStatus and returns an AsyncStatus that is run after handleRejected
  • onReset function?: a function that receives an AsyncStatus and returns an AsyncStatus that is run after handleReset
adapter.handlePending(thunk)(state);

Return Value

createAsyncAdapter returns an object that looks like this:

{
  getInitialState: <T>(initialData: T) => AsyncState<T>,
  getSelectors: () => ({
    selectStatus: (state: AsyncState, thunk: AsyncThunk) => AsyncStatus,
    selectAllStatuses: (state: AsyncState) => AsyncStatus[],
    selectAnyLoading: (state: AsyncState) => boolean,
    selectAllErrors: (state: AsyncState) => SerializedError[],
    selectAllFinished: (state: AsyncState) => boolean
  }),
  handlePending: (thunk: AsyncThunk) => (state: AsyncState) => void,
  handleFulfilled: (thunk: AsyncThunk) => (state: AsyncState) => void,
  handleRejected: (thunk: AsyncThunk) => (state: AsyncState, action: AsyncThunk['rejected']) => void,
}

State

  • getInitialState: accepts a initialData parameter of any type and return an AsyncState with that initial data and an empty status array
const initialState = adapter.getInitialState({});
// initialState is { status: {}, data: {} }

Handlers

All handlers accept an asyncThunk (created by redux toolkit's createAsyncThunk) and return a reducer that can be used to update the status for that thunk.

  • handlePending: accepts an asyncThunk and return a reducer that reset error and loaded state and set loading to true for that thunk.
adapter.handlePending(thunk)(state);
  • handleFulfilled: accepts an asyncThunk and return a reducer that reset error and loading state and set loaded to true and update lastLoaded timestamp (ISO formatted)
adapter.handleFulfilled(thunk)(state);
  • handleRejected: accepts an asyncThunk and return a reducer that reset loaded and loading state and update the error field with the error provided in the action
adapter.handleRejected(thunk)(state, action);
  • handleReset: accepts an asyncThunk and return a reducer that reset the loading and loaded state to false and reset the error and last loaded fields
adapter.handleReset(thunk)(state);
  • resetAllStatuses: a reducer that reset all of the loading statuses previously stored
adapter.resetAllStatuses(state);

Selectors

  • selectData: select the data in the state (e.g. the data that you passed when using getInitialState)
adapter.getSelectors().selectData(state);
  • selectStatus: accepts an asyncThunk (created by redux toolkit's createAsyncThunk) and returns a selector that accepts a state and returns the status object of that particular thunk
adapter.getSelectors().selectStatus(thunk)(state);
  • selectAllStatuses: returns an array of all status objects within the state
adapter.getSelectors().selectAllStatuses(state);
  • selectAnyLoading: returns whether or not any thunks within the state is currently loading
adapter.getSelectors().selectAnyLoading(state);
  • selectAllErrors: returns a list of all the errors in the state
adapter.getSelectors().selectAllErrors(state);
  • selectAllFinished: returns whether or not all thunk in the state has finished (loaded)
adapter.getSelectors().selectAllFinished(state);