{"id":13902800,"url":"https://github.com/vladagurets/react-cancelable","last_synced_at":"2025-07-18T00:32:09.403Z","repository":{"id":37073285,"uuid":"458578260","full_name":"vladagurets/react-cancelable","owner":"vladagurets","description":"⚜️ Make cancelable requests with react-hooks","archived":true,"fork":false,"pushed_at":"2023-02-15T21:01:29.000Z","size":888,"stargazers_count":62,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-07-11T14:46:22.577Z","etag":null,"topics":["cancelable","react","request"],"latest_commit_sha":null,"homepage":"https://vladagurets.github.io/react-cancelable/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vladagurets.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-02-12T16:34:30.000Z","updated_at":"2024-05-22T02:16:46.000Z","dependencies_parsed_at":"2023-02-16T22:45:55.311Z","dependency_job_id":null,"html_url":"https://github.com/vladagurets/react-cancelable","commit_stats":{"total_commits":119,"total_committers":2,"mean_commits":59.5,"dds":"0.025210084033613467","last_synced_commit":"e7e830d074e48274b630fd61d20b8966cc82da78"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladagurets%2Freact-cancelable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladagurets%2Freact-cancelable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladagurets%2Freact-cancelable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladagurets%2Freact-cancelable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vladagurets","download_url":"https://codeload.github.com/vladagurets/react-cancelable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":214260289,"owners_count":15707074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cancelable","react","request"],"created_at":"2024-08-06T22:01:25.270Z","updated_at":"2024-08-06T22:04:05.926Z","avatar_url":"https://github.com/vladagurets.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://www.supportukraine.co/)\n\n\u003ch1 align=\"center\"\u003ereact-cancelable\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003ci\u003eInternet traffic economizer\u003c/i\u003e\u003c/span\u003e\n\u003cbr\u003e\u003c/br\u003e\n\n\u003cbr /\u003e\n\n[![version][npm-version-badge]][npm-url]\n[![downloads][weekly-downloads-badge]][npm-url]\n\u003c!-- [![downloads][total-downloads-badge]][npm-url] --\u003e\n\n[npm-url]: https://www.npmjs.com/package/react-cancelable\n[npm-version-badge]: https://badge.fury.io/js/react-cancelable.svg\n[total-downloads-badge]: https://img.shields.io/npm/dt/react-cancelable.svg\n[weekly-downloads-badge]: https://img.shields.io/npm/dm/react-cancelable.svg\n\n\u003cbr /\u003e\n\n# Table of Contents\n\n1. [Motivation](#motivation)\n2. [Instalation](#instalation)\n3. [Tools](#tools)\n    1. [useCancelableReq](#usecancelablereq)\n    2. [useCancelableImg](#usecancelableimg)\n    3. [cancelable HOF](#cancelable-hof)\n4. [Fetch vs Axios](#fetch-vs-axios)\n5. [Best practices (WIP)](#best-practices)\n\n\u003cbr /\u003e\n\n# Motivation\n\nIn most of cases client consumes a lot of excess internet 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.\n\n\u003c!-- But don't worry you can easily deal with it with the latest AbortController API and react-cancelable --\u003e\n\nWith react-cancelable you can easily cancel requests at any step of the [request's lifecycle](https://dev.to/dangolant/things-i-brushed-up-on-this-week-the-http-request-lifecycle-) and consume fewer traffic bytes.\n\n\u003cbr /\u003e\n\n# Instalation\n\n```\nnpm install react-cancelable\n```\n```\nyarn add react-cancelable\n```\n\n  \u003cbr /\u003e\n\nBefore installation be sure you have installed the required peer dependencies to your project\n\n\u003cbr /\u003e\n\n```json\n{\n  \"react\": \"^17.0.0\",\n}\n```\n\n\u003cbr /\u003e\n\n# Tools\n\n\u003cbr /\u003e\n\n## useCancelableReq\n\n\u003cbr /\u003e\n\nMake cancelable request. Hook helps you to control request canceling by React Component Lifecycle or by your own.\n\n\u003cbr /\u003e\n\n### Signature\n\n\u003cbr /\u003e\n\n```typescript\ntype RequestFn = (controller: AbortController) =\u003e Promise\u003cany\u003e\n\ntype Opts = {\n  isLazy?: boolean;\n  cancelOnUnmount?: boolean;\n  controller?: AbortController;\n  onComplete?: (res: any) =\u003e void;\n  onFail?: (error: any) =\u003e void\n  onCancel?: VoidFunction;\n}\n\ntype Artefacts = {\n  res?: Response;\n  data?: any;\n  error?: any;\n  isLoading: boolean;\n  cancel: VoidFunction,\n  makeLazyRequest: VoidFunction | null;\n}\n\nuseCancelableReq(fn: RequestFn, opts?: Opts): Artefacts\n```\n\n\u003cbr /\u003e\n\n### API\n\u003cbr /\u003e\n\u003ctable width=\"100%\"\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eName\u003c/th\u003e\n      \u003cth\u003eDescription\u003c/th\u003e\n      \u003cth\u003eDefault\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eisLazy\u003c/td\u003e\n      \u003ctd\u003eControl request by your own if true. By default, a request will be made on the component mount\u003c/td\u003e\n      \u003ctd\u003efalse\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ecancelOnUnmount\u003c/td\u003e\n      \u003ctd\u003eRequest will be canceled on component unmount if true\u003c/td\u003e\n      \u003ctd\u003etrue\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003econtroller\u003c/td\u003e\n      \u003ctd\u003eBy 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\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eonComplete\u003c/td\u003e\n      \u003ctd\u003eTrigger after request is completed\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eonFail\u003c/td\u003e\n      \u003ctd\u003eTrigger after request is failed\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eonCancel\u003c/td\u003e\n      \u003ctd\u003eTrigger after request is canceled\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eres\u003c/td\u003e\n      \u003ctd\u003eResponse object\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n     \u003ctr\u003e\n    \u003ctd\u003edata\u003c/td\u003e\n      \u003ctd\u003ePayload of a request\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eerror\u003c/td\u003e\n      \u003ctd\u003eError of a request\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eisLoading\u003c/td\u003e\n      \u003ctd\u003eFlag to determine active status of request. If isLazy is true isLoading is false by default\u003c/td\u003e\n      \u003ctd\u003etrue\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ecancel\u003c/td\u003e\n      \u003ctd\u003eRequest cancel trigger\u003c/td\u003e\n      \u003ctd\u003efunction\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003emakeLazyRequest\u003c/td\u003e\n      \u003ctd\u003eMake request trigger. If isLazy is true makeLazyRequest is function\u003c/td\u003e\n      \u003ctd\u003enull\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003cbr /\u003e\n\n### Example\n\n\u003cbr /\u003e\n\n```jsx\nimport React from 'react'\nimport { useCancelableReq } from 'react-cancelable'\n\nfunction makeRequest(controller) {\n  // Pass signal to your request\n  return fetch(\"YOUR_ENDPOINT\", { signal: controller.signal })\n}\n\nfunction Item() {\n  const { data, isLoading, error } = useCancelableReq(makeRequest)\n\n  return (\n    \u003c\u003e\n      {isLoading \u0026\u0026 \u003cspan\u003eLoading...\u003c/span\u003e}\n      {error \u0026\u0026 \u003cspan\u003eError occured\u003c/span\u003e}\n      {data \u0026\u0026 \u003cspan\u003eData is fetched\u003c/span\u003e}\n    \u003c/\u003e\n  )\n}\n```\n\n\u003cbr /\u003e\n\n## useCancelableImg\n\n\u003cbr /\u003e\n\nMake cancelable request. Hook helps you to cancel requested image.\n\n\u003cbr /\u003e\n\n### Signature\n\n\u003cbr /\u003e\n\n```typescript\ntype RequestFn = (controller: AbortController) =\u003e Promise\u003cany\u003e\n\ntype Opts = {\n  isLazy?: boolean;\n  cancelOnUnmount?: boolean;\n  controller?: AbortController;\n  onComplete?: (res: any) =\u003e void;\n  onFail?: (error: any) =\u003e void\n  onCancel?: VoidFunction;\n}\n\ntype Artefacts = {\n  res?: Response;\n  src?: string;\n  error?: any;\n  isLoading: boolean;\n  cancel: VoidFunction,\n  makeLazyRequest: VoidFunction | null;\n}\n\nuseCancelableImg(fn: RequestFn, opts?: Opts): Artefacts\n```\n\n\u003cbr /\u003e\n\n### API\n\u003cbr /\u003e\n\u003ctable width=\"100%\"\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eName\u003c/th\u003e\n      \u003cth\u003eDescription\u003c/th\u003e\n      \u003cth\u003eDefault\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eisLazy\u003c/td\u003e\n      \u003ctd\u003eControl request by your own if true. By default, a request will be made on the component mount\u003c/td\u003e\n      \u003ctd\u003efalse\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ecancelOnUnmount\u003c/td\u003e\n      \u003ctd\u003eRequest will be canceled on component unmount if true\u003c/td\u003e\n      \u003ctd\u003etrue\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003econtroller\u003c/td\u003e\n      \u003ctd\u003eBy 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\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eonComplete\u003c/td\u003e\n      \u003ctd\u003eTrigger after request is completed\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eonFail\u003c/td\u003e\n      \u003ctd\u003eTrigger after request is failed\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eonCancel\u003c/td\u003e\n      \u003ctd\u003eTrigger after request is canceled\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eres\u003c/td\u003e\n      \u003ctd\u003eResponse object\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003esrc\u003c/td\u003e\n      \u003ctd\u003eGenerated ObjectURI to Blob image after request done\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eerror\u003c/td\u003e\n      \u003ctd\u003eError of a request\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eisLoading\u003c/td\u003e\n      \u003ctd\u003eFlag to determine active status of request. If isLazy is true isLoading is false by default\u003c/td\u003e\n      \u003ctd\u003etrue\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ecancel\u003c/td\u003e\n      \u003ctd\u003eRequest cancel trigger\u003c/td\u003e\n      \u003ctd\u003efunction\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003emakeLazyRequest\u003c/td\u003e\n      \u003ctd\u003eMake request trigger. If isLazy is true makeLazyRequest is function\u003c/td\u003e\n      \u003ctd\u003enull\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003cbr /\u003e\n\n### Example\n\n\u003cbr /\u003e\n\n```jsx\nimport React from 'react'\nimport { useCancelableReq } from 'react-cancelable'\n\n\nfunction getImage(controller) {\n  // Pass signal to your request\n  return fetch('IMAGE_URL', { signal: controller.signal })\n}\n\nfunction Item() {\n  const { src, isLoading, error } = useCancelableImg(getImage)\n\n  return (\n    \u003c\u003e\n      {isLoading \u0026\u0026 \u003cspan\u003eLoading...\u003c/span\u003e}\n      {src \u0026\u0026 \u003cimg src={src} /\u003e}\n    \u003c/\u003e\n  )\n}\n```\n\n\u003cbr /\u003e\n\n## cancelable HOF\n\u003cbr /\u003e\n\nHight order function to create cancelable requests\n\n\u003cbr /\u003e\n\n### Signature\n\n\u003cbr /\u003e\n\n```typescript\ntype RequestFn = (controller: AbortController) =\u003e Promise\u003cany\u003e\n\ntype RequestPromise = Promise\u003cany\u003e \u0026 { cancel: VoidFunction }\n\ncancelable(fn: RequestFn, controller?: AbortController): RequestPromise\n```\n\n\u003cbr /\u003e\n\n### API\n\n\u003cbr /\u003e\n\n\u003ctable width=\"100%\"\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eName\u003c/th\u003e\n      \u003cth\u003eDescription\u003c/th\u003e\n      \u003cth\u003eDefault\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003efn\u003c/td\u003e\n      \u003ctd\u003eCallback that returns Promise generated by HTTP client\u003c/td\u003e\n      \u003ctd\u003efunction\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003econtroller\u003c/td\u003e\n      \u003ctd\u003eBy 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\u003c/td\u003e\n      \u003ctd\u003eundefined\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ecancel\u003c/td\u003e\n      \u003ctd\u003eRequest cancel trigger. Property added to returned Promise\u003c/td\u003e\n      \u003ctd\u003efunction\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003cbr /\u003e\n\n### Example\n\n\u003cbr /\u003e\n\n```javascript\nimport { cancelable } from 'react-cancelable'\n\nfunction makeRequest(controller) {\n  return fetch(\"YOUR_ENDPOINT\", { signal: controller.signal })\n}\n\n// Wrap your request\nconst request = cancelable(makeRequest)\n\nsetTimeout(() =\u003e {\n  // Cancel request later\n  request.cancel()\n}, 1000)\n```\n\n\u003cbr /\u003e\n\n# Fetch vs Axios\n\nThere is no difference what HTTP client you use. Package have one important rule - HTTP client must accept [AbortController signal](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal).\n\n```javascript\nfunction makeFetchRequest(controller) {\n  return fetch(\"YOUR_ENDPOINT\", { signal: controller.signal })\n}\n\nfunction makeAxiosRequest(controller) {\n  return axios.get(\"YOUR_ENDPOINT\", { signal: controller.signal })\n}\n```\n\n\u003cbr /\u003e\n\n# Best practices (WIP)\n\nCancel multiple similar request via one AbortController. Each helper can take ```controller``` parameter.\n\n```javascript\nimport { cancelable } from 'react-cancelable'\n\nconst controller = new AbortController()\n\nfunction makeRequest(controller) {\n  return fetch(\"YOUR_ENDPOINT\", { signal: controller.signal })\n}\n\n// Make requests\nnew Array(100).fill(0).forEach(() =\u003e { cancelable(makeRequest, controller) } )\n\nsetTimeout(() =\u003e {\n  // Stop all pending requests\n  controller.abort()\n}, 1000)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladagurets%2Freact-cancelable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvladagurets%2Freact-cancelable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladagurets%2Freact-cancelable/lists"}