├── .eslintrc
├── .gitignore
├── .prettierignore
├── LICENSE.md
├── README.md
├── demo
└── src
│ └── index.js
├── nwb.config.js
├── package-lock.json
├── package.json
└── src
├── FetchProvider.js
├── index.js
├── useFetch.js
└── utils.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "react-app",
3 | "plugins": ["react-hooks"],
4 | "rules": {
5 | "react-hooks/rules-of-hooks": "error"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /demo/dist
3 | /es
4 | /lib
5 | /node_modules
6 | /umd
7 | npm-debug.log*
8 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | README.md
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Bjørnar G. Hveding
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @bjornagh/use-fetch
2 |
3 | An easy-to-use React hook for doing `fetch` requests.
4 |
5 | ## Features
6 |
7 | - 1️⃣ Dedupes requests done to the same endpoint. Only one request to the same endpoint will be initiated.
8 | - 💨 Caches responses to improve speed and reduce amount of requests.
9 | - 🛀 Automatically makes new requests if URL changes.
10 | - ⚛️ Small size, with only two dependencies: `react` and `fetch-dedupe`.
11 |
12 | ## Install
13 |
14 | ```bash
15 | npm install @bjornagh/use-fetch
16 |
17 | # if yarn
18 | yarn add @bjornagh/use-fetch
19 | ```
20 |
21 | ## Usage
22 |
23 | 1. Create a cache (new Map()) and render the `FetchProvider` at the top of your application.
24 |
25 | ```jsx
26 | import { FetchProvider } from "@bjornagh/use-fetch";
27 |
28 | const cache = new Map();
29 |
30 | ReactDOM.render(
31 |
32 |
33 | ,
34 | document.getElementById("container")
35 | );
36 | ```
37 |
38 | 2. Use `useFetch` in your component
39 |
40 | ```jsx
41 | import React from "react";
42 | import { useFetch } from "@bjornagh/use-fetch";
43 |
44 | function MyComponent() {
45 | const { data, fetching } = useFetch({
46 | url: "https://jsonplaceholder.typicode.com/todos"
47 | });
48 |
49 | return (
50 |
54 | );
55 | }
56 | ```
57 |
58 | See more examples in the examples section [examples section ](https://github.com/bghveding/use-fetch#Examples).
59 |
60 | ## API
61 | `useFetch` accepts an object that supports the following properties
62 |
63 | | Key | Default value | Description |
64 | |------|--------------|--------------|
65 | | url | | URL to send request to |
66 | | method | GET | HTTP method |
67 | | lazy | null | Lazy mode determines if a request should be done on mount and when the request parameters change (e.g. URL) or not. When null only GET requests are initiated when mounted and if for example the URL changes. If `true` this applies to all requests regardless of HTTP method. If `false`, requests are only initiated manually by calling `doFetch`, a function returned by `useFetch`|
68 | | init | {} | See https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch `init` argument for which keys are supported |
69 | | dedupeOptions | {} | See https://github.com/jamesplease/fetch-dedupe#user-content-api `dedupeOptions` argument for which keys are supported |
70 | | cacheResponse | true if read request, false if write | Cache response or not |
71 | | requestKey | null | requestKey is used as cache key and to prevent duplicate requests. Generated automatically if nothing is passed. |
72 | | cachePolicy | null | [Caching strategy](https://github.com/bghveding/use-fetch#cachepolicy) |
73 | | refreshDoFetch | Function | By default doFetch method is memoized (by `useCallback`) by using the request (url+method+body). Use this to override if you get a stale doFetch. It receives one argument, the default request key. e.g. `requestKey => requestKey + 'something'` |
74 | | onError | Function | A callback function that is called anytime a fetch fails. Receives an `Error` as only argument. Logs to console by default |
75 | | onSuccess | Function | A callback function that is called anytime a fetch succeeds. Receives a fetch [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) as only argument. Does nothing by default (noop) |
76 |
77 | Return value
78 |
79 | | Key | type | Description |
80 | |------|-------------|---------------|
81 | | response | [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) | [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) |
82 | | data | * | Request data response |
83 | | fetching | Boolean | Whether request is in-flight or not |
84 | | error | [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) | Any errors from `fetch` |
85 | | requestKey | String | The key used as cache key and to prevent duplicate requests |
86 | | doFetch | Function | A function to initiate a request manually. Takes one argument: `init`, an object that is sent to `fetch`. See https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch (`init` argument for which keys are supported). Returns a promise. |
87 |
88 | NOTE: Requests with `Content-type` set to `application/json` will automatically have their body
89 | stringified (`JSON.stringify`)
90 |
91 | ### `cachePolicy`
92 | * `cache-first` - Uses response in cache if available. Makes request if not.
93 | * `cache-and-network` - Uses response in cache if available, but will also always make a new request in the background in order to refresh any stale data.
94 | * `exact-cache-and-network` - Similar to `cache-and-network`, but will only show cached response if the requests are identical (url+method+body).
95 | * `network-only` - Ignores cache and always makes a request.
96 |
97 | Read requests (GET, OPTIONS, HEAD) default to `cache-first`.
98 |
99 | Write requests (POST, DELETE, PUT, PATCH) default to `network-only`.
100 |
101 | ## Examples
102 |
103 | ### POST request and update view afterwards
104 |
105 | ```jsx
106 | function Demo() {
107 | // Fetch list of posts
108 | const posts = useFetch({
109 | url: "https://jsonplaceholder.typicode.com/posts"
110 | });
111 |
112 | // Prepare create request
113 | // This will not be initiated until you call `createPost.doFetch()`
114 | const createPost = useFetch({
115 | url: "https://jsonplaceholder.typicode.com/posts",
116 | method: "POST",
117 | init: {
118 | headers: {
119 | "Content-type": "application/json"
120 | }
121 | }
122 | });
123 |
124 | return (
125 |
153 | );
154 | }
155 | ```
156 |
157 | ### Delay fetching using the `lazy` prop
158 |
159 | Setting the `lazy` parameter to `true` tells `useFetch` to not start requesting on mount or when
160 | the request parameters change.
161 |
162 | You can change this at any time. A common pattern where this feature is useful is when you want the
163 | user to apply some filters before you initiate a request.
164 |
165 | Below is an example where a request is delayed until a search input contains at least two characters.
166 |
167 | ```jsx
168 | function LazyDemo() {
169 | const [searchFilter, setSearchFilter] = useState("");
170 | const posts = useFetch({
171 | url: `/posts?search=${searchFilter}`,
172 | lazy: searchFilter.length < 2 // Request is lazy as long as the input has less than two characters
173 | });
174 |
175 | return (
176 |