Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-async-hook

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-async-hook - npm Package Compare versions

Comparing version 2.3.0 to 3.0.0

10

dist/index.d.ts

@@ -9,2 +9,3 @@ export declare type AsyncState<R> = {

declare type SetError<R> = (error: Error, asyncState: AsyncState<R>) => AsyncState<R>;
declare type MaybePromise<T> = Promise<T> | T;
export declare type UseAsyncOptionsNormalized<R> = {

@@ -19,10 +20,11 @@ initialState: () => AsyncState<R>;

export declare type UseAsyncOptions<R> = Partial<UseAsyncOptionsNormalized<R>> | undefined | null;
export declare type UseAsyncReturn<R> = AsyncState<R> & {
export declare type UseAsyncReturn<R, Args extends any[]> = AsyncState<R> & {
set: (value: AsyncState<R>) => void;
execute: () => Promise<R>;
execute: (...args: Args) => Promise<R>;
currentPromise: Promise<R> | null;
};
export declare const useAsync: <R, Args extends any[]>(asyncFunction: (...args: Args) => Promise<R>, params: Args, options?: UseAsyncOptions<R>) => UseAsyncReturn<R>;
export declare const useAsync: <R, Args extends any[]>(asyncFunction: (...args: Args) => Promise<R>, params: Args, options?: UseAsyncOptions<R>) => UseAsyncReturn<R, Args>;
declare type AddArg<H, T extends any[]> = ((h: H, ...t: T) => void) extends ((...r: infer R) => void) ? R : never;
export declare const useAsyncAbortable: <R, Args extends any[]>(asyncFunction: (...args: AddArg<AbortSignal, Args>) => Promise<R>, params: Args, options?: UseAsyncOptions<R>) => UseAsyncReturn<R>;
export declare const useAsyncAbortable: <R, Args extends any[]>(asyncFunction: (...args: AddArg<AbortSignal, Args>) => Promise<R>, params: Args, options?: UseAsyncOptions<R>) => UseAsyncReturn<R, Args>;
export declare const useAsyncCallback: <R, Args extends any[]>(asyncFunction: (...args: Args) => MaybePromise<R>) => UseAsyncReturn<R, Args>;
export {};

60

dist/react-async-hook.cjs.development.js

@@ -61,3 +61,5 @@ 'use strict';

};
const useAsync = (asyncFunction, params, options) => {
// Relaxed interface which accept both async and sync functions
// Accepting sync function is convenient for useAsyncCallback
const useAsyncInternal = (asyncFunction, params, options) => {
const normalizedOptions = normalizeOptions(options);

@@ -70,16 +72,24 @@ const AsyncState = useAsyncState(normalizedOptions);

const shouldHandlePromise = (p) => isMounted() && CurrentPromise.is(p);
const executeAsyncOperation = () => {
const promise = asyncFunction(...params);
CurrentPromise.set(promise);
AsyncState.setLoading();
promise.then(result => {
if (shouldHandlePromise(promise)) {
AsyncState.setResult(result);
}
}, error => {
if (shouldHandlePromise(promise)) {
AsyncState.setError(error);
}
});
return promise;
const executeAsyncOperation = (...args) => {
const promise = asyncFunction(...args);
if (promise instanceof Promise) {
CurrentPromise.set(promise);
AsyncState.setLoading();
promise.then(result => {
if (shouldHandlePromise(promise)) {
AsyncState.setResult(result);
}
}, error => {
if (shouldHandlePromise(promise)) {
AsyncState.setError(error);
}
});
return promise;
}
else {
// We allow passing a non-async function (mostly for useAsyncCallback conveniency)
const syncResult = promise;
AsyncState.setResult(syncResult);
return Promise.resolve(syncResult);
}
};

@@ -91,6 +101,6 @@ // Keep this outside useEffect, because inside isMounted()

if (isMounting) {
normalizedOptions.executeOnMount && executeAsyncOperation();
normalizedOptions.executeOnMount && executeAsyncOperation(...params);
}
else {
normalizedOptions.executeOnUpdate && executeAsyncOperation();
normalizedOptions.executeOnUpdate && executeAsyncOperation(...params);
}

@@ -105,2 +115,3 @@ }, params);

};
const useAsync = (asyncFunction, params, options) => useAsync(asyncFunction, params, options);
const useAsyncAbortable = (asyncFunction, params, options) => {

@@ -131,5 +142,20 @@ const abortControllerRef = react.useRef();

};
const useAsyncCallback = (asyncFunction) => {
return useAsyncInternal(asyncFunction,
// Hacky but in such case we don't need the params,
// because async function is only executed manually
[], {
executeOnMount: false,
executeOnUpdate: false,
initialState: () => ({
loading: false,
result: undefined,
error: undefined,
}),
});
};
exports.useAsync = useAsync;
exports.useAsyncAbortable = useAsyncAbortable;
exports.useAsyncCallback = useAsyncCallback;
//# sourceMappingURL=react-async-hook.cjs.development.js.map

@@ -1,2 +0,2 @@

"use strict";var e=require("react");const t={loading:!0,result:void 0,error:void 0},r={initialState:()=>t,executeOnMount:!0,executeOnUpdate:!0,setLoading:e=>t,setResult:(e,t)=>({loading:!1,result:e,error:void 0}),setError:(e,t)=>({loading:!1,result:void 0,error:e})},n=(t,n,s)=>{const u=(e=>({...r,...e}))(s),o=(t=>{const[r,n]=e.useState(t.initialState);return{value:r,set:n,setLoading:()=>n(t.setLoading(r)),setResult:e=>n(t.setResult(e,r)),setError:e=>n(t.setError(e,r))}})(u),c=(()=>{const t=e.useRef(!1);return e.useEffect(()=>(t.current=!0,()=>{t.current=!1}),[]),()=>t.current})(),i=(()=>{const t=e.useRef(null);return{set:e=>t.current=e,get:()=>t.current,is:e=>t.current===e}})(),a=e=>c()&&i.is(e),l=()=>{const e=t(...n);return i.set(e),o.setLoading(),e.then(t=>{a(e)&&o.setResult(t)},t=>{a(e)&&o.setError(t)}),e},d=!c();return e.useEffect(()=>{d?u.executeOnMount&&l():u.executeOnUpdate&&l()},n),{...o.value,set:o.set,execute:l,currentPromise:i.get()}};exports.useAsync=n,exports.useAsyncAbortable=((t,r,s)=>{const u=e.useRef();return n(async(...e)=>{u.current&&u.current.abort();const r=new AbortController;u.current=r;try{return await t(r.signal,...e)}finally{u.current===r&&(u.current=void 0)}},r,s)});
"use strict";var e=require("react");const t={loading:!0,result:void 0,error:void 0},r={initialState:()=>t,executeOnMount:!0,executeOnUpdate:!0,setLoading:e=>t,setResult:(e,t)=>({loading:!1,result:e,error:void 0}),setError:(e,t)=>({loading:!1,result:void 0,error:e})},s=(t,s,n)=>{const u=(e=>({...r,...e}))(n),o=(t=>{const[r,s]=e.useState(t.initialState);return{value:r,set:s,setLoading:()=>s(t.setLoading(r)),setResult:e=>s(t.setResult(e,r)),setError:e=>s(t.setError(e,r))}})(u),c=(()=>{const t=e.useRef(!1);return e.useEffect(()=>(t.current=!0,()=>{t.current=!1}),[]),()=>t.current})(),i=(()=>{const t=e.useRef(null);return{set:e=>t.current=e,get:()=>t.current,is:e=>t.current===e}})(),a=e=>c()&&i.is(e),l=(...e)=>{const r=t(...e);if(r instanceof Promise)return i.set(r),o.setLoading(),r.then(e=>{a(r)&&o.setResult(e)},e=>{a(r)&&o.setError(e)}),r;{const e=r;return o.setResult(e),Promise.resolve(e)}},d=!c();return e.useEffect(()=>{d?u.executeOnMount&&l(...s):u.executeOnUpdate&&l(...s)},s),{...o.value,set:o.set,execute:l,currentPromise:i.get()}},n=(e,t,r)=>n(e,t,r);exports.useAsync=n,exports.useAsyncAbortable=((t,r,s)=>{const u=e.useRef();return n(async(...e)=>{u.current&&u.current.abort();const r=new AbortController;u.current=r;try{return await t(r.signal,...e)}finally{u.current===r&&(u.current=void 0)}},r,s)}),exports.useAsyncCallback=(e=>s(e,[],{executeOnMount:!1,executeOnUpdate:!1,initialState:()=>({loading:!1,result:void 0,error:void 0})}));
//# sourceMappingURL=react-async-hook.cjs.production.js.map

@@ -1,2 +0,2 @@

import{useEffect as t,useRef as e,useState as r}from"react";const n={loading:!0,result:void 0,error:void 0},o={initialState:()=>n,executeOnMount:!0,executeOnUpdate:!0,setLoading:t=>n,setResult:(t,e)=>({loading:!1,result:t,error:void 0}),setError:(t,e)=>({loading:!1,result:void 0,error:t})},s=(n,s,u)=>{const c=(t=>({...o,...t}))(u),i=(t=>{const[e,n]=r(t.initialState);return{value:e,set:n,setLoading:()=>n(t.setLoading(e)),setResult:r=>n(t.setResult(r,e)),setError:r=>n(t.setError(r,e))}})(c),a=(()=>{const r=e(!1);return t(()=>(r.current=!0,()=>{r.current=!1}),[]),()=>r.current})(),l=(()=>{const t=e(null);return{set:e=>t.current=e,get:()=>t.current,is:e=>t.current===e}})(),d=t=>a()&&l.is(t),g=()=>{const t=n(...s);return l.set(t),i.setLoading(),t.then(e=>{d(t)&&i.setResult(e)},e=>{d(t)&&i.setError(e)}),t},v=!a();return t(()=>{v?c.executeOnMount&&g():c.executeOnUpdate&&g()},s),{...i.value,set:i.set,execute:g,currentPromise:l.get()}},u=(t,r,n)=>{const o=e();return s(async(...e)=>{o.current&&o.current.abort();const r=new AbortController;o.current=r;try{return await t(r.signal,...e)}finally{o.current===r&&(o.current=void 0)}},r,n)};export{s as useAsync,u as useAsyncAbortable};
import{useRef as e,useEffect as t,useState as r}from"react";const n={loading:!0,result:void 0,error:void 0},o={initialState:()=>n,executeOnMount:!0,executeOnUpdate:!0,setLoading:e=>n,setResult:(e,t)=>({loading:!1,result:e,error:void 0}),setError:(e,t)=>({loading:!1,result:void 0,error:e})},s=(n,s,u)=>{const i=(e=>({...o,...e}))(u),c=(e=>{const[t,n]=r(e.initialState);return{value:t,set:n,setLoading:()=>n(e.setLoading(t)),setResult:r=>n(e.setResult(r,t)),setError:r=>n(e.setError(r,t))}})(i),a=(()=>{const r=e(!1);return t(()=>(r.current=!0,()=>{r.current=!1}),[]),()=>r.current})(),l=(()=>{const t=e(null);return{set:e=>t.current=e,get:()=>t.current,is:e=>t.current===e}})(),d=e=>a()&&l.is(e),g=(...e)=>{const t=n(...e);if(t instanceof Promise)return l.set(t),c.setLoading(),t.then(e=>{d(t)&&c.setResult(e)},e=>{d(t)&&c.setError(e)}),t;{const e=t;return c.setResult(e),Promise.resolve(e)}},v=!a();return t(()=>{v?i.executeOnMount&&g(...s):i.executeOnUpdate&&g(...s)},s),{...c.value,set:c.set,execute:g,currentPromise:l.get()}},u=(e,t,r)=>u(e,t,r),i=(t,r,n)=>{const o=e();return u(async(...e)=>{o.current&&o.current.abort();const r=new AbortController;o.current=r;try{return await t(r.signal,...e)}finally{o.current===r&&(o.current=void 0)}},r,n)},c=e=>s(e,[],{executeOnMount:!1,executeOnUpdate:!1,initialState:()=>({loading:!1,result:void 0,error:void 0})});export{u as useAsync,i as useAsyncAbortable,c as useAsyncCallback};
//# sourceMappingURL=react-async-hook.es.production.js.map

@@ -63,3 +63,5 @@ (function (global, factory) {

};
const useAsync = (asyncFunction, params, options) => {
// Relaxed interface which accept both async and sync functions
// Accepting sync function is convenient for useAsyncCallback
const useAsyncInternal = (asyncFunction, params, options) => {
const normalizedOptions = normalizeOptions(options);

@@ -72,16 +74,24 @@ const AsyncState = useAsyncState(normalizedOptions);

const shouldHandlePromise = (p) => isMounted() && CurrentPromise.is(p);
const executeAsyncOperation = () => {
const promise = asyncFunction(...params);
CurrentPromise.set(promise);
AsyncState.setLoading();
promise.then(result => {
if (shouldHandlePromise(promise)) {
AsyncState.setResult(result);
}
}, error => {
if (shouldHandlePromise(promise)) {
AsyncState.setError(error);
}
});
return promise;
const executeAsyncOperation = (...args) => {
const promise = asyncFunction(...args);
if (promise instanceof Promise) {
CurrentPromise.set(promise);
AsyncState.setLoading();
promise.then(result => {
if (shouldHandlePromise(promise)) {
AsyncState.setResult(result);
}
}, error => {
if (shouldHandlePromise(promise)) {
AsyncState.setError(error);
}
});
return promise;
}
else {
// We allow passing a non-async function (mostly for useAsyncCallback conveniency)
const syncResult = promise;
AsyncState.setResult(syncResult);
return Promise.resolve(syncResult);
}
};

@@ -93,6 +103,6 @@ // Keep this outside useEffect, because inside isMounted()

if (isMounting) {
normalizedOptions.executeOnMount && executeAsyncOperation();
normalizedOptions.executeOnMount && executeAsyncOperation(...params);
}
else {
normalizedOptions.executeOnUpdate && executeAsyncOperation();
normalizedOptions.executeOnUpdate && executeAsyncOperation(...params);
}

@@ -107,2 +117,3 @@ }, params);

};
const useAsync = (asyncFunction, params, options) => useAsync(asyncFunction, params, options);
const useAsyncAbortable = (asyncFunction, params, options) => {

@@ -133,7 +144,22 @@ const abortControllerRef = react.useRef();

};
const useAsyncCallback = (asyncFunction) => {
return useAsyncInternal(asyncFunction,
// Hacky but in such case we don't need the params,
// because async function is only executed manually
[], {
executeOnMount: false,
executeOnUpdate: false,
initialState: () => ({
loading: false,
result: undefined,
error: undefined,
}),
});
};
exports.useAsync = useAsync;
exports.useAsyncAbortable = useAsyncAbortable;
exports.useAsyncCallback = useAsyncCallback;
}));
//# sourceMappingURL=react-async-hook.umd.development.js.map

@@ -1,2 +0,2 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):(e=e||self,t(e["react-async-hook"]={},e.React))}(this,function(e,t){"use strict";const r={loading:!0,result:void 0,error:void 0},n={initialState:()=>r,executeOnMount:!0,executeOnUpdate:!0,setLoading:e=>r,setResult:(e,t)=>({loading:!1,result:e,error:void 0}),setError:(e,t)=>({loading:!1,result:void 0,error:e})},s=(e,r,s)=>{const u=(e=>({...n,...e}))(s),o=(e=>{const[r,n]=t.useState(e.initialState);return{value:r,set:n,setLoading:()=>n(e.setLoading(r)),setResult:t=>n(e.setResult(t,r)),setError:t=>n(e.setError(t,r))}})(u),c=(()=>{const e=t.useRef(!1);return t.useEffect(()=>(e.current=!0,()=>{e.current=!1}),[]),()=>e.current})(),i=(()=>{const e=t.useRef(null);return{set:t=>e.current=t,get:()=>e.current,is:t=>e.current===t}})(),a=e=>c()&&i.is(e),l=()=>{const t=e(...r);return i.set(t),o.setLoading(),t.then(e=>{a(t)&&o.setResult(e)},e=>{a(t)&&o.setError(e)}),t},d=!c();return t.useEffect(()=>{d?u.executeOnMount&&l():u.executeOnUpdate&&l()},r),{...o.value,set:o.set,execute:l,currentPromise:i.get()}};e.useAsync=s,e.useAsyncAbortable=((e,r,n)=>{const u=t.useRef();return s(async(...t)=>{u.current&&u.current.abort();const r=new AbortController;u.current=r;try{return await e(r.signal,...t)}finally{u.current===r&&(u.current=void 0)}},r,n)})});
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):(e=e||self,t(e["react-async-hook"]={},e.React))}(this,function(e,t){"use strict";const r={loading:!0,result:void 0,error:void 0},n={initialState:()=>r,executeOnMount:!0,executeOnUpdate:!0,setLoading:e=>r,setResult:(e,t)=>({loading:!1,result:e,error:void 0}),setError:(e,t)=>({loading:!1,result:void 0,error:e})},s=(e,r,s)=>{const o=(e=>({...n,...e}))(s),u=(e=>{const[r,n]=t.useState(e.initialState);return{value:r,set:n,setLoading:()=>n(e.setLoading(r)),setResult:t=>n(e.setResult(t,r)),setError:t=>n(e.setError(t,r))}})(o),c=(()=>{const e=t.useRef(!1);return t.useEffect(()=>(e.current=!0,()=>{e.current=!1}),[]),()=>e.current})(),i=(()=>{const e=t.useRef(null);return{set:t=>e.current=t,get:()=>e.current,is:t=>e.current===t}})(),a=e=>c()&&i.is(e),l=(...t)=>{const r=e(...t);if(r instanceof Promise)return i.set(r),u.setLoading(),r.then(e=>{a(r)&&u.setResult(e)},e=>{a(r)&&u.setError(e)}),r;{const e=r;return u.setResult(e),Promise.resolve(e)}},d=!c();return t.useEffect(()=>{d?o.executeOnMount&&l(...r):o.executeOnUpdate&&l(...r)},r),{...u.value,set:u.set,execute:l,currentPromise:i.get()}},o=(e,t,r)=>o(e,t,r);e.useAsync=o,e.useAsyncAbortable=((e,r,n)=>{const s=t.useRef();return o(async(...t)=>{s.current&&s.current.abort();const r=new AbortController;s.current=r;try{return await e(r.signal,...t)}finally{s.current===r&&(s.current=void 0)}},r,n)}),e.useAsyncCallback=(e=>s(e,[],{executeOnMount:!1,executeOnUpdate:!1,initialState:()=>({loading:!1,result:void 0,error:void 0})}))});
//# sourceMappingURL=react-async-hook.umd.production.js.map
{
"name": "react-async-hook",
"version": "2.3.0",
"version": "3.0.0",
"description": "Async hook",

@@ -5,0 +5,0 @@ "author": "Sébastien Lorber",

@@ -7,3 +7,3 @@ # React-async-hook

- Simplest way to get async result in your React component
- Very good, native, typescript support
- Very good, native, Typescript support
- Refetch on params change

@@ -15,4 +15,14 @@ - Handle concurrency issues if params change too fast

- Options to customize state updates
- Handle async callbacks (mutations)
## Usecase: loading async data into a component
The ability to inject remote/async data into a React component is a very common React need. Later we might support Suspense as well.
```tsx
import { useAsync } from 'react-async-hook';
const fetchStarwarsHero = async id =>
(await fetch(`https://swapi.co/api/people/${id}/`)).json();
const StarwarsHero = ({ id }) => {

@@ -35,19 +45,33 @@ const asyncHero = useAsync(fetchStarwarsHero, [id]);

And the typesafe async function could be:
## Usecase: injecting async feedback into buttons
If you have a Todo app, you might want to show some feedback into the "create todo" button while the creation is pending, and prevent duplicate todo creations by disabling the button.
Just wire `useAsyncCallback` to your `onClick` prop in your primitive `AppButton` component. The library will show a feedback only if the button onClick callback is async, otherwise it won't do anything.
```tsx
type StarwarsHero = {
id: string;
name: string;
import { useAsyncCallback } from "react-async-hook";
const AppButton = ({ onClick, children }) => {
const asyncOnClick = useAsyncCallback(onClick);
return (
<button onClick={asyncOnClick.execute} disabled={asyncOnClick.loading}>
{asyncOnClick.loading ? "..." : children}
</div>
);
};
const fetchStarwarsHero = async (id: string): Promise<StarwarsHero> => {
const result = await fetch(`https://swapi.co/api/people/${id}/`);
if (result.status !== 200) {
throw new Error('bad status = ' + result.status);
}
return result.json();
};
const CreateTodoButton = () => (
<AppButton
onClick={async () => {
await createTodoAPI("new todo text")
}}
>
Create Todo
</AppButton>
)
```
# Examples
Examples are running on [this page](https://react-async-hook.netlify.com/) and [implemented here](https://github.com/slorber/react-async-hook/blob/master/example/index.tsx) (in Typescript)

@@ -54,0 +78,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc