redux-waiter

0.5.0 • Public • Published

Redux Waiter

NPM Build Status

Installation

npm i redux-waiter --save

This gives you access to the reducer, constants, actions, and selectors available.

Add to your combineReducers()

import { reducer } from 'redux-waiter';
 
const initialState = combineReducers({
  waiter: reducer,
});
 
const store = createStore(
  initialState,
  {},
  compose(applyMiddleware(...[thunk]))
);

NOTE: Ensure you have redux-thunk configured as middleware in your store implementation

Waiter model description and defaults

Each waiter initialized will have these properties.

const model = {
  // incremented after each request
  id: 0,
 
  // your waiter's name
  name: null,
 
  // your request to track
  requestCreator: null,
 
  // the params for your request to use
  params: null,
 
  // the promise returned from the requestCreator
  request: null,
 
  // the result of the promise
  response: null,
 
  // the error if returned from the promise
  error: null,
 
  // true if the request is called a second time and isPending
  isRefreshing: false,
 
  // true when the request is pending
  isPending: false,
 
  // true when the request returns an error
  isRejected: false,
 
  // true when the request returns successfully
  isResolved: false,
 
  // true if the request resolves or rejects
  isCompleted: false,
 
  // true if the request is canceled
  isCanceled: false,
 
  // true if the request rejected, and is being called again
  isRetrying: false,
 
  // start time of request in milliseconds UTC
  startTime: null,
 
  // end time of request in milliseconds UTC
  endTime: null,
 
  // difference in milliseconds of start and end times
  elapsedTime: null,
 
  // last time the model changed in milliseconds UTC
  lastModified: null,
 
  // how many times the request has been called and returned an error
  // resets after a successful response
  attempts: 0,
};

connectWaiter

import { connectWaiter } from 'redux-waiter'

connectWaiter is a higher-order-component that connects your waiter promise to another component. You can listen in on waiter events and dispatch other actions. You can add custom views to different waiter states, as well as add custom actions to the mount and unmount lifecycle events

Below is the full interface for connectWaiter, ordered in the sequence that the actions take place

import { connectWaiter } from 'redux-waiter';
import MyComponent from 'path/to/MyComponent';
import notification from 'path/to/notification';
 
const SearchRequestForm = connectWaiter({
  /* 
   * Configuration settings 
   */
 
  // name can be a string or a function with access to props 
  name: (props) => 'my-waiter-name',
 
  // requestCreator, your promise builder 
  requestCreator: (params, props) => yourAPI.getSomething(params),
 
  /* 
   * Alternate views 
   */
 
  pendingView: LoadingView,
  rejectedView: FailureView,
 
  /* 
   * Lifecycle configs and state change callbacks
   */
 
  // onMount
  onMount: (waiter, props) => {
    // Hey, we mounted!
    console.log('onMount', waiter)
  },
 
  // clear the waiter data when the component is added to the view
  clearOnMount: true,
 
  // create your promise request when mounting your component
  requestOnMount: true,
 
  // pass parameters to the request creator based on props
  requestOnMountParams: (props) => ({ name: 'First', last: 'Last' }),
 
  // like requestOnMountParams, but used to initialize the call to
  // the waiter again on props change
  requestOnPropsChange: (props) => ({ name: 'First', last: 'Last' }),
 
  // state change callbacks 
  onPending: (waiter, props) => {
    // And we're off! 
    console.log('onPending - ', waiter);
  },
  onResolve: (waiter, props) => {
    // Success!
    console.log('onResolve - ', waiter.response);
  },
  onReject: (waiter, props) => {
    // Oh no...error
    console.log('onReject - ', waiter.error);
  },
  onComplete: (waiter, props) => {
    // All done!
    console.log('onComplete - ', waiter);
  },
  onRefresh: (waiter, props) => {
    // We're updating our response!
    console.log('onRefresh - ', waiter)
  },
  onCancel: (waiter, props) => {
    // The waiter canceled, do what you need to clean up 
    console.log('onCancel - ', waiter)
  },
 
  // on unmount
  onUnmount: (waiter, props) => {
    // Say goodbye to your view! 
    console.log('onUnmount - ', waiter);
  },
 
  // clear the waiter data when the component is removed from view
  clearOnUnmount: true,
 
})(MyComponent);

Actions

callWaiter(waiterName, { params, requestCreator })

The call action will invoke the requestCreator with the supplied params and store all waiter processes to the waiterName given.

import { callWaiter } from 'redux-waiter';
 
dispatch(
  callWaiter('get-toy', {
    requestCreator: (params) => getToyPromise(params.id),
    params: { id: '1' },
  })
);

prepareWaiter(waiterName, { params, requestCreator })

Prepare is the same as callWaiter, but it will only store up the params and request creator to the waiterName. It will not invoke the requestCreator until callWaiter(waiterName) is dispatched

import { prepareWaiter } from 'redux-waiter'

dispatch(
  prepareWaiter('get-toy', {
    requestCreator: (params) => getToyPromise(params.id),
    params: { id: '1'}
  })
)

// then somewhere else you can call it
dispatch(callWaiter('get-toy'))

clearWaiter(waiterName)

Clear will reset the waiter as if it was never called. This removes all params, response, and error data. The waiter stays in the store and can be used again.

import { clearWaiter } from 'redux-waiter';
 
// In your redux environment
dispatch(clearWaiter('waiter-name'));

clearAll()

Clear all the waiters in the store.

import { clearAll } from 'redux-waiter';
 
// In you redux environment
dispatch(clearAll());

destroyWaiter(waiterName)

Destroy will remove the waiter from the store. It will not longer be accessible unless initialized again.

import { destroyWaiter } from 'redux-waiter';
 
// In you redux environment
dispatch(destroyWaiter('waiter-name'));

destroyAll()

Destroy all the waiters in the store.

import { destroyAll } from 'redux-waiter';
 
// In you redux environment
dispatch(destroyAll());

Selectors

getWaiter(state, waiterName)

Get the waiter model from the store by it's name.

import { getWaiter } from 'redux-waiter';
 
// In your mapStateToProps somewhere
(state) => getWaiter(state, 'get-toy');

getWaiterResponse(state, waiterName)

Get only the response of the promise by the waiter name. Returns null if no response has been set.

import { getWaiterResponse } from 'redux-waiter';
 
// In your mapStateToProps somewhere
(state) => getWaiterResponse(state, 'get-toy');

getWaiterError(state, waiterName)

Get only the error of the promise by the waiter name. Returns null if no error has been set.

import { getWaiterError } from 'redux-waiter';
 
// In your mapStateToProps somewhere
(state) => getWaiterError(state, 'get-toy');

Example

Valid Document Link

Create your component with the connectWaiter

import React from 'react';
import axios from 'axios';
 
import { connectWaiter } from 'redux-waiter';
 
const ValidUrlLink = connectWaiter({
  // dynamic waiter name using props
  name: (props) => `link:${props.url}`,
 
  requestCreator: (params) => axios({ url: params.url }),
  requestOnMountParams: (props) => ({ url: props.url }),
 
  // alternate views for the Promise lifecycle
  pendingView: () => <span>...</span>,
  rejectedView: () => <span>Invalid link</span>,
})((props) => <a href={props.url}>Click to View</a>);

Implement your component in the JSX

... <ValidUrlLink url="https://link.to.pdf" />' ...

Dependencies

Due to the asynchronous nature of this library, redux-waiter requires that you have redux-thunk configured as middleware for your store.

Readme

Keywords

Package Sidebar

Install

npm i redux-waiter

Weekly Downloads

63

Version

0.5.0

License

MIT

Unpacked Size

83.1 kB

Total Files

26

Last publish

Collaborators

  • billyxs