Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/davidje13/react-hook-awaited
A helper for working with asynchronous data in react functional components.
https://github.com/davidje13/react-hook-awaited
Last synced: about 1 month ago
JSON representation
A helper for working with asynchronous data in react functional components.
- Host: GitHub
- URL: https://github.com/davidje13/react-hook-awaited
- Owner: davidje13
- License: mit
- Created: 2020-12-06T21:34:12.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2022-08-14T18:43:12.000Z (over 2 years ago)
- Last Synced: 2024-11-20T21:56:51.677Z (about 1 month ago)
- Language: JavaScript
- Homepage:
- Size: 17.6 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# React useAwaited hook
A helper for working with asynchronous data in react functional components.
See the [examples](#examples) for some use cases.
## Install dependency
```bash
npm install --save react-hook-awaited
```## Usage
```jsx
const useAwaited = require('react-hook-awaited');const MyComponent = () => {
const apiUrl = 'https://xkcd.com/info.0.json';
const apiResponse = useAwaited((signal) => fetch(apiUrl, { signal }).then((r) => r.json()), [apiUrl]);switch (apiResponse.state) {
case 'pending':
return (Loading...);
case 'resolved':
return (Latest: {apiResponse.data.num});
case 'rejected':
return (
Failed: {apiResponse.error}
Try Again
);
}
};
```If you are using [eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks),
you should configure it to check dependencies for `useAwaited` and
`useAwaitedWithDefault`:```json
"react-hooks/exhaustive-deps": ["warn", {
"additionalHooks": "(useAwaited|useAwaitedWithDefault)"
}]
```Alternatively, you can provide functions using `useCallback` yourself
(this requires more syntax but avoids the need to reconfigure the linter):```js
const apiResponse = useAwaited(
useCallback(
(signal) => fetch(apiUrl, { signal }).then((r) => r.json()),
[apiUrl]
)
);
```## API
### useAwaited(generatorFunction, deps)
```javascript
const value = useAwaited(generatorFunction, deps);
```Invokes the `generatorFunction` and returns the state of the returned
promise.- `generatorFunction`: a function which returns a promise which is
to be awaited. It is passed a single argument: an
[AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
which will be marked as aborted if a change means that the current
request is no-longer required.
- `deps`: a list of dependencies for the `generatorFunction`, matching
the same API as
[`React.useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback).The `AbortSignal` can be passed directly to `fetch` calls to avoid
leaving requests running which are no-longer required:```js
useAwaited((abortSignal) => fetch('https://example.com', { signal: abortSignal }), []);
```**note:** If the `deps` change, the current promise will be discarded,
the `AbortSignal` will be triggered, `generatorFunction` will be called
again, and the newly returned promise will be awaited.If you do not provide `deps`, the default is to re-invoke the generator
whenever the generator function changes. This means you can pass a
`useCallback`-wrapped function _instead of_ providing `deps`.#### Return value
The response is an object which contains several properties:
- `state`: one of `'pending'`, `'resolved'` or `'rejected'`. For
convenience these are also exported as constants `PENDING`,
`RESOLVED`, `REJECTED`.
- `data`: the current data returned by the promise (if `state` is
`'resolved'`, otherwise `undefined`).
- `error`: the current error returned by the promise (if `state` is
`'rejected'`, otherwise `undefined`).
- `stats`: an object containing statistics about the current promise:
- `beginTimestamp`: time when the promise began (number of
milliseconds since the epoch)
- `endTimestamp`: time when the promise completed (number of
milliseconds since the epoch), or undefined if `state` is
`pending`.
- `latestData`: the last successfully resolved data. Unlike `data`,
this continues to be available until new data replaces it.
This is `undefined` until the first request succeeds.
- `latestStats`: an object containing statistics about the last
completed promise. Unlike `stats`, this continues to be available
while new data is loaded. This is `undefined` until the first
request has completed.
- `forceRefresh`: a function which can be called to force an
immediate refresh of the data. This function is guaranteed to be
stable (will be the same function instance across all renders).### useAwaitedWithDefault(default, generatorFunction, deps)
Same as `useAwaited`, but `latestData` will be initialised as
`default` rather than `undefined`.## Examples
### Loading data from a dynamic API endpoint
```jsx
const useAwaited = require('react-hook-awaited');const ComicViewer = () => {
const [num, setNum] = useState(1);
const apiUrl = `https://xkcd.com/${num}/info.0.json`;
const apiResponse = useAwaited((signal) => fetch(apiUrl, { signal }).then((r) => r.json()), [apiUrl]);let content;
if (apiResponse.state === 'pending') {
content = (Loading...);
} else if (apiResponse.state === 'rejected') {
content = (
Failed to load #{num}: {apiResponse.error}
Try Again
);
} else {
content = (
{apiResponse.data.title}
);
}
return (
Show XKCD
{ content }
);
};
```### Show latest data with user-controlled refresh
```jsx
const useAwaited = require('react-hook-awaited');const DataFetcher = () => {
const apiUrl = 'https://xkcd.com/info.0.json';
const apiResponse = useAwaited((signal) => fetch(apiUrl, { signal }).then((r) => r.json()), [apiUrl]);let content = null;
if (apiResponse.latestData) {
content = (
Latest: {apiResponse.latestData.num}
(as of ${new Date(apiResponse.latestStats.endTimestamp).toString()})
);
}
return (
{content}
{apiResponse.state === 'pending' ? (
Refreshing...
) : (
Refresh
)}
{apiResponse.state === 'rejected' ? (
Failed to refresh: ${apiResponse.error}
) : null}
);
};
```### Automatically refreshing on an interval
This also uses [react-hook-final-countdown](https://github.com/davidje13/react-hook-countdown)
```jsx
const useAwaited = require('react-hook-awaited');
const {useTimeInterval} = require('react-hook-final-countdown');const DataFetcher = () => {
const apiUrl = 'https://xkcd.com/info.0.json';
const time = useTimeInterval(1000 * 60 * 60); // update every hour
const apiResponse = useAwaited((signal) => fetch(apiUrl, { signal }).then((r) => r.json()), [apiUrl, time]);return (
Latest: {apiResponse.latestData?.num}
(as of ${new Date(apiResponse.latestStats?.endTimestamp).toString()})
);
};
```