Skip to content

Commit 258d696

Browse files
committed
feat: 🎸 add useAsync hook
1 parent 7c29826 commit 258d696

File tree

6 files changed

+109
-1
lines changed

6 files changed

+109
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
## Reference
3232

3333
- [__Sensors__](./docs/Sensors.md)
34-
- [`useBattery`](./docs/useBattery.md) — tracks device batter state.
34+
- [`useBattery`](./docs/useBattery.md) — tracks device battery state.
3535
- [`useGeolocation`](./docs/useGeolocation.md) — tracks geo location state of user's device.
3636
- [`useHover`](./docs/useHover.md) — tracks mouse hover state of some element.
3737
- [`useIdle`](./docs/useIdle.md) — tracks whether user is being inactive.
@@ -53,6 +53,7 @@
5353
<br/>
5454
<br/>
5555
- [__Side-effects__](./docs/Side-effects.md)
56+
- [`useAsync`](./docs/useAsync.md) &mdash; resolves an `async` function.
5657
- [`useCss`](./docs/useCss.md) &mdash; dynamically adjusts CSS.
5758
- [`useFavicon`](./docs/useFavicon.md) &mdash; sets favicon of the page.
5859
- [`useTitle`](./docs/useTitle.md) &mdash; sets title of the page.

docs/useAsync.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# `useAsync`
2+
3+
React hook that resolves an `async` function or a function that returns
4+
a promise;
5+
6+
7+
## Usage
8+
9+
```jsx
10+
import {useAsync} from 'react-use';
11+
12+
// Returns a Promise that resolves after one second.
13+
const fn = () => new Promise((resolve) => {
14+
setTimeout(() => {
15+
resolve('RESOLVED');
16+
}, 1000);
17+
});
18+
19+
const Demo = () => {
20+
const {loading, value, error} = useAsync(fn);
21+
22+
return (
23+
<div>
24+
{loading
25+
? <div>Loading...</div>
26+
: <div>Value: {value}</div>
27+
}
28+
</div>
29+
);
30+
};
31+
```

src/__stories__/useAsync.story.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from 'react';
2+
import {storiesOf} from '@storybook/react';
3+
import {useAsync} from '..';
4+
5+
const fn = () => new Promise((resolve) => {
6+
setTimeout(() => {
7+
resolve('RESOLVED');
8+
}, 1000);
9+
});
10+
11+
const Demo = () => {
12+
const {loading, value} = useAsync(fn);
13+
14+
return (
15+
<div>
16+
{loading
17+
? <div>Loading...</div>
18+
: <div>Value: {value}</div>
19+
}
20+
</div>
21+
);
22+
};
23+
24+
storiesOf('useAsync', module)
25+
.add('Example', () =>
26+
<Demo/>
27+
)

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import useAsync from './useAsync';
12
import useBattery from './useBattery';
23
import useCounter from './useCounter';
34
import useCss from './useCss';
@@ -23,6 +24,7 @@ import useTween from './useTween';
2324
import useWindowSize from './useWindowSize';
2425

2526
export {
27+
useAsync,
2628
useBattery,
2729
useCounter,
2830
useCss,

src/react.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ export const useEffect: UseEffect = (React as any).useEffect;
88

99
export type UseRef = <T>(initialValue: T) => {current: T};
1010
export const useRef: UseRef = (React as any).useRef;
11+
12+
export type UseCallback = <T extends ((...args: any[]) => any)>(callback: T, args: any[]) => T;
13+
export const useCallback: UseCallback = (React as any).useCallback;

src/useAsync.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {useState, useEffect, useCallback} from './react';
2+
3+
export interface AsyncState<T> {
4+
loading: boolean;
5+
error?: Error | any;
6+
value?: T;
7+
}
8+
9+
const useAsync = <T>(fn: () => Promise<T>, args?) => {
10+
const [state, set] = useState<AsyncState<T>>({
11+
loading: true,
12+
});
13+
const memoized = useCallback(fn, args);
14+
15+
useEffect(() => {
16+
let mounted = true;
17+
const promise = memoized();
18+
19+
promise
20+
.then(value => {
21+
if (mounted) {
22+
set({
23+
loading: false,
24+
value,
25+
});
26+
}
27+
}, error => {
28+
if (mounted) {
29+
set({
30+
loading: false,
31+
error,
32+
});
33+
}
34+
});
35+
36+
return () => {
37+
mounted = false;
38+
};
39+
}, [memoized]);
40+
41+
return state;
42+
};
43+
44+
export default useAsync;

0 commit comments

Comments
 (0)