react-cancelable

Make cancelable requests with react-hooks

Usage no npm install needed!

<script type="module">
  import reactCancelable from 'https://cdn.skypack.dev/react-cancelable';
</script>

README

react-cancelable(alpha)

Improve client's traffic experiense


version


Table of Contents

  1. Motivation
  2. Instalation
  3. Tools
    1. useCancelableReq
    2. useCancelableImg
    3. cancelable HOF
  4. Fetch vs Axios
  5. Best practices (WIP)

Motivation

In most of cases client consumes a lot of excess traffic. Modern web applications make a huge bunch of requests per conventional time unit then a lot of clients don't wait until all requests made by web app are finished. As a result, the browser expects data that will no longer be used

But don't worry you can easily deal with it with the latest AbortController API and react-cancelable


Instalation

npm install react-cancelable
yarn add react-cancelable

Before installation be sure you have installed the required peer dependencies to your project


{
  "react": "^17.0.0",
}

Tools


useCancelableReq


Make cancelable request. Hook helps you to control request canceling by React Component Lifecycle or by your own.


Signature


type RequestFn = (controller: AbortController) => Promise<any>

type Opts = {
  isLazy?: boolean;
  cancelOnUnmount?: boolean;
  controller?: AbortController;
  onComplete?: (res: any) => void;
  onFail?: (error: any) => void
  onCancel?: VoidFunction;
}

type Artefacts = {
  res?: Response;
  data?: any;
  error?: any;
  isLoading: boolean;
  cancel: VoidFunction,
  makeLazyRequest: VoidFunction | null;
}

useCancelableReq(fn: RequestFn, opts?: Opts): Artefacts

API


Name Description Default
isLazy Control request by your own if true. By default, a request will be made on the component mount false
cancelOnUnmount Request will be canceled on component unmount if true true
controller By default component will create instance automaticaly under the hood. If yoo want to controll multiple requests with one conteroller pass your own instance of AbortControler undefined
onComplete Trigger after request is completed undefined
onFail Trigger after request is failed undefined
onCancel Trigger after request is canceled undefined
res Response object undefined
data Payload of a request undefined
error Error of a request undefined
isLoading Flag to determine active status of request. If isLazy is true isLoading is false by default true
cancel Request cancel trigger function
makeLazyRequest Make request trigger. If isLazy is true makeLazyRequest is function null

Example


import React from 'react'
import { useCancelableReq } from 'react-cancelable'

function makeRequest(controller) {
  // Pass signal to your request
  return fetch("YOUR_ENDPOINT", { signal: controller.signal })
}

const opts = {}

function Item() {
  const { data, isLoading, error } = useCancelableReq(makeRequest)

  return (
    <>
      {isLoading && <span>Loading...</span>}
      {error && <span>Error occured</span>}
      {data && <span>Data is fetched</span>}
    </>
  )
}

useCancelableImg


Make cancelable request. Hook helps you to cancel requested image.


Signature


type RequestFn = (controller: AbortController) => Promise<any>

type Opts = {
  isLazy?: boolean;
  cancelOnUnmount?: boolean;
  controller?: AbortController;
  onComplete?: (res: any) => void;
  onFail?: (error: any) => void
  onCancel?: VoidFunction;
}

type Artefacts = {
  res?: Response;
  src?: string;
  error?: any;
  isLoading: boolean;
  cancel: VoidFunction,
  makeLazyRequest: VoidFunction | null;
}

useCancelableImg(fn: RequestFn, opts?: Opts): Artefacts

API


Name Description Default
isLazy Control request by your own if true. By default, a request will be made on the component mount false
cancelOnUnmount Request will be canceled on component unmount if true true
controller By default component will create instance automaticaly under the hood. If yoo want to controll multiple requests with one conteroller pass your own instance of AbortControler undefined
onComplete Trigger after request is completed undefined
onFail Trigger after request is failed undefined
onCancel Trigger after request is canceled undefined
res Response object undefined
src Generated ObjectURI to Blob image after request done undefined
error Error of a request undefined
isLoading Flag to determine active status of request. If isLazy is true isLoading is false by default true
cancel Request cancel trigger function
makeLazyRequest Make request trigger. If isLazy is true makeLazyRequest is function null

Example


import React from 'react'
import { useCancelableReq } from 'react-cancelable'


function getImage(controller) {
  // Pass signal to your request
  return fetch('IMAGE_URL', { signal: controller.signal })
}

function Item() {
  const { src, isLoading, error } = useCancelableImg(getImage)

  return (
    <>
      {isLoading && <span>Loading...</span>}
      {src && <img src={src} />}
    </>
  )
}

cancelable HOF


Hight order function to create cancelable requests


Signature


type RequestFn = (controller: AbortController) => Promise<any>

type RequestPromise = Promise<any> & { cancel: VoidFunction }

cancelable(fn: RequestFn, controller?: AbortController): RequestPromise

API


Name Description Default
fn Callback that returns Promise generated by HTTP client function
controller By default component will create instance automaticaly under the hood. If yoo want to controll multiple requests with one conteroller pass your own instance of AbortControler undefined
cancel Request cancel trigger. Property added to returned Promise function

Example


import { cancelable } from 'react-cancelable'

function makeRequest(controller) {
  return fetch("YOUR_ENDPOINT", { signal: controller.signal })
}

// Wrap your request
const request = cancelable(makeRequest)

setTimeout(() => {
  // Cancel request later
  request.cancel()
}, 1000)

Fetch vs Axios

There is no difference what HTTP client you use. Package have one important rule - HTTP client must accept AbortController signal.

function makeFetchRequest(controller) {
  return fetch("YOUR_ENDPOINT", { signal: controller.signal })
}

function makeAxiosRequest(controller) {
  return axios.get("YOUR_ENDPOINT", { signal: controller.signal })
}

Best practices (WIP)

Cancel multiple similar request via one AbortController. Each helper can take controller parameter.

import { cancelable } from 'react-cancelable'

const controller = new AbortController()

function makeRequest(controller) {
  return fetch("YOUR_ENDPOINT", { signal: controller.signal })
}

// Make requests
new Array(100).fill(0).forEach(() => { cancelable(makeRequest, controller) } )

setTimeout(() => {
  // Stop all pending requests
  controller.abort()
}, 1000)