Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include 'abort' functionality in order to cancel fetch request #59

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3245893
feat-> example
Paola3stefania Oct 8, 2022
9c47199
feat-> fix example
Paola3stefania Oct 8, 2022
add7b17
feat-> comments on abort solution
Cherrerotinoco Oct 8, 2022
e187b12
fix->basic example
Cherrerotinoco Oct 8, 2022
b83994a
feat-> abort function
Paola3stefania Oct 8, 2022
dfdcc31
feat -> example basic version 2
Cherrerotinoco Oct 8, 2022
12ace92
feat-> conditional result promise
Cherrerotinoco Oct 8, 2022
b6bf318
feat-> abort null case
Paola3stefania Oct 8, 2022
d16e580
feat-> example abort
Paola3stefania Oct 8, 2022
ae2efea
feat-> abort done
Cherrerotinoco Oct 8, 2022
d347911
fix-> clean code
Paola3stefania Oct 8, 2022
58aa1b8
remove -> comments
Cherrerotinoco Oct 8, 2022
ab52261
remove -> comments
Paola3stefania Oct 8, 2022
d93593b
readme-> codesandbox
Paola3stefania Oct 8, 2022
88824b1
Readme updates abort
Paola3stefania Oct 8, 2022
137d3c3
update -> example readme.md
Cherrerotinoco Oct 9, 2022
5562840
change -> readme title
Cherrerotinoco Oct 9, 2022
6236e2a
change -> increase size limit
Cherrerotinoco Oct 9, 2022
e76068b
fix -> eslint issues
Cherrerotinoco Oct 9, 2022
c1f9210
fix-> better example
Paola3stefania Oct 9, 2022
a205745
feat-> types
Paola3stefania Oct 9, 2022
492bb6e
feat-> final readme docu
Paola3stefania Oct 9, 2022
fa5247f
fix-> readme
Paola3stefania Oct 9, 2022
3d281c8
fix -> missing comma
Cherrerotinoco Oct 9, 2022
67c02fe
Merge branch 'master' of https://github.com/Cherrerotinoco/react-fetc…
Cherrerotinoco Oct 9, 2022
aaafaeb
fix -> missing comma
Cherrerotinoco Oct 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 65 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const { isLoading, data } = useFetch("https://swapi.co/api/people/1", {

### Error handling

The `useFetch` hook returns an `error` field at any fetch exception.
The `useFetch` hook returns an `error` field at any fetch exception.
The `error` field extends [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
and has `status` and `statusText` fields equal to [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).

Expand All @@ -72,12 +72,63 @@ const Component = () => {
<p>Message: ${error.statusText}</p>
</div>
}

...
};

```


### Abort request

The `useFetch` hook returns an `abort()` function that can be implemented whenever you need to cancel the request.
You can pass custom option: `{abortController: true}` to use this funcionality.
`abort` implements the Abort Controller Interface [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
You can see it in codesandbox-> [Code](https://codesandbox.io/s/react-fetch-hook-basic-forked-zb820v)

```javascript
...

const Component = () => {

const defaultUrl = "https://swapi.dev/api/people/1";
const [url, useUrl] = useState(defaultUrl);
const [fetchUrl, useFetchUrl] = useState(defaultUrl);


const { isLoading, data, abort } = useFetch(fetchUrl, {
abortController: true,
});

const handleOnClick = (event) => {
event.preventDefault();
console.log("Fetching...");
useFetchUrl(url);
};

return (
<div>
<input
id="url"
type="text"
name="url"
onChange={(event) => useUrl(event.target.value)}
placeholder={"Url to fetch"}
value={url}
/>
<button onClick={handleOnClick}>Fecth Url</button>
<button onClick={() => abort()}>Abort</button>
<p>isLoading: {(isLoading && "true") || "false"}</p>
<p>Name: {data && data.name}</p>
</div>
);



};
...

```

### Multiple requests
Multiple `useFetch` in the same file/component supported:

Expand All @@ -87,7 +138,7 @@ const result2 = useFetch("https://swapi.co/api/people/2");

if (result1.isLoading && result2.isLoading) {
return <div>Loading...</div>;
}
}

return <div>
<UserProfile {...result1.data} />
Expand Down Expand Up @@ -116,17 +167,17 @@ import useTrigger from "react-use-trigger/useTrigger";

const requestTrigger = createTrigger();

export const Subscriber = () => {
export const Subscriber = () => {
const requestTriggerValue = useTrigger(requestTrigger);

const { isLoading, data } = useFetch("https://swapi.co/api/people/1", {
depends: [requestTriggerValue]
});

return <div />;
}

export const Sender = () => {
export const Sender = () => {
return <button onClick={() => {
requestTrigger() // re-call request
}}>Send</button>
Expand Down Expand Up @@ -157,18 +208,20 @@ const Component = () => {
* [Basic](examples/basic) - Just fetch data with `useFetch`.
* [Depends](examples/depends) - Usage `depends` option for refresh query.
* [Pagination](examples/pagination) - Usage `usePaginationRequest` for infinite scroll implementation.
* [Abort](examples/abort) - Usage `abortController:true` for aborting promises .

## API

### `useFetch`
Create a hook wrapper for `fetch` call.
Create a hook wrapper for `fetch` call.
```javascript
useFetch(
path: RequestInfo,
options?: {
...RequestOptions,
formatter?: Response => Promise
depends?: Array<boolean>
abortController: Boolean
},
specialOptions?: {
formatter?: Response => Promise
Expand All @@ -182,6 +235,7 @@ where `TUseFetchResult` is:
data: any,
isLoading: boolean,
error: any
abort: any,
}
```

Expand All @@ -201,13 +255,14 @@ type TUsePromiseResult<T> = {
data: ?T,
isLoading: boolean,
error: mixed
abort: mixed
}
```

### Experimental: `usePaginatedRequest`
⚠️ Warning: this method is experimental, API can be changed.

Create a paginated request.
Create a paginated request.
```javascript
usePaginatedRequest = <T>(
request: (params: { limit: number, offset: number }) => Promise<Array<T>>,
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
* [Basic](basic) - Just fetch data with `useFetch`.
* [Depends](depends) - Usage `depends` option for refresh query.
* [Pagination](pagination) - Usage `usePaginationRequest` for infinite scroll implementation.
* [Abort](abort) - Usage `abort` for cancel a current fetch call.
9 changes: 9 additions & 0 deletions examples/abort/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Abort

![Abort example](basic.gif)

Just fetch data with `useFetch`.

Try at CodeSandbox:

[![Edit basic](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-fetch-hook-basic-forked-zb820v)
Binary file added examples/abort/abort.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions examples/abort/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="root"></div>
<script src="./index.js"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions examples/abort/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState } from "react";
import ReactDOM from "react-dom";
import useFetch from "../../index";

const App = () => {
const defaultUrl = "https://swapi.dev/api/people/1";
const [url, useUrl] = useState(defaultUrl);
const [fetchUrl, useFetchUrl] = useState(defaultUrl);

const { isLoading, data, abort } = useFetch(fetchUrl, {
abortController: true,
});

const handleOnClick = (event) => {
event.preventDefault();
console.log("Fetching...");
useFetchUrl(url);
};

return (
<div>
<input
id="url"
type="text"
name="url"
onChange={(event) => useUrl(event.target.value)}
placeholder={"Url to fetch"}
value={url}
/>
<button onClick={handleOnClick}>Fecth Url</button>
<button onClick={() => abort()}>Abort</button>
<p>isLoading: {(isLoading && "true") || "false"}</p>
<p>Name: {data && data.name}</p>
</div>
);
};

if (root) {
ReactDOM.render(<App />, document.getElementById("root"));
}
2 changes: 1 addition & 1 deletion examples/basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Just fetch data with `useFetch`.

Try at CodeSandbox:

[![Edit basic](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-fetch-hook-basic-g1in5)
[![Edit basic](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-fetch-hook-basic-forked-jzhjw7)
40 changes: 28 additions & 12 deletions examples/basic/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import React from "react";
import React, { useState } from "react";
import ReactDOM from "react-dom";
import useFetch from "../../index";


const App = () => {
const {isLoading, data, error} = useFetch(`https://swapi.co/api/people/1`);
const defaultUrl = "https://swapi.dev/api/people/1";
const [url, useUrl] = useState(defaultUrl);
const [fetchUrl, useFetchUrl] = useState(defaultUrl);

const { isLoading, data, error } = useFetch(fetchUrl);

console.log(isLoading, data, error && error.status);
const handleOnClick = (event) => {
useFetchUrl(event.target.url.value);
event.preventDefault(); // 👈️ prevent page refresh
// 👇️ clear all input values in the form
useUrl("");
};

return <div>
<p>isLoading: {isLoading && "true" || "false"}</p>
<p>Name: {data && data.name}</p>
return (
<div>
<input
id="url"
type="text"
name="url"
onChange={(event) => useUrl(event.target.value)}
placeholder={"Url to fetch"}
value={url}
/>
<button onClick={handleOnClick}>Fecth Url</button>

<p>isLoading: {(isLoading && "true") || "false"}</p>
<p>Name: {data && data.name}</p>
</div>
);
};


if (root) {
ReactDOM.render(
<App />,
document.getElementById("root")
);
ReactDOM.render(<App />, document.getElementById("root"));
}
3 changes: 2 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ declare namespace useFetch {
export interface FetchResult<T> {
data?: T,
isLoading: boolean,
error?: UseFetchError
error?: UseFetchError,
abort?: any
}

export interface HookOptions extends RequestInit {
Expand Down
4 changes: 3 additions & 1 deletion index.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ type TUseFetchResult<T> = {
error?: Error & {
status: number,
statusText: string
}
},
abort: any
};

declare function useFetch<T>(path: RequestInfo, options?: { ...RequestOptions,
formatter?: (Response) => Promise<T>,
depends?: Array<mixed>,
Expand Down
Loading