1 | [![SWR](https://assets.zeit.co/image/upload/v1572289618/swr/banner.png)](https://swr.now.sh)
|
2 |
|
3 | <p align="center">
|
4 | <a aria-label="ZEIT logo" href="https://github.com/zeit">
|
5 | <img src="https://img.shields.io/badge/MADE%20BY%20ZEIT-000000.svg?logo=ZEIT&labelColor=000000&logoWidth=12">
|
6 | </a>
|
7 | <a aria-label="NPM version" href="https://www.npmjs.com/package/swr">
|
8 | <img alt="" src="https://img.shields.io/npm/v/swr">
|
9 | </a>
|
10 | <a aria-label="Package size" href="https://bundlephobia.com/result?p=swr">
|
11 | <img alt="" src="https://img.shields.io/bundlephobia/minzip/swr">
|
12 | </a>
|
13 | <a aria-label="License" href="https://github.com/zeit/swr/blob/master/LICENSE">
|
14 | <img alt="" src="https://img.shields.io/npm/l/swr">
|
15 | </a>
|
16 | </p>
|
17 |
|
18 | ## Introduction
|
19 |
|
20 | [swr.now.sh](https://swr.now.sh)
|
21 |
|
22 | SWR is a React Hooks library for remote data fetching.
|
23 |
|
24 | The name “**SWR**” is derived from `stale-while-revalidate`, a HTTP cache invalidation strategy popularized by [RFC 5861](https://tools.ietf.org/html/rfc5861).
|
25 | **SWR** first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.
|
26 |
|
27 | It features:
|
28 | - Transport and protocol agnostic data fetching
|
29 | - Fast page navigation
|
30 | - Revalidation on focus
|
31 | - Interval polling
|
32 | - Local mutation
|
33 | - Pagination
|
34 | - TypeScript ready
|
35 | - Suspense mode
|
36 | - React Native support
|
37 | - Minimal API
|
38 |
|
39 | ...and a lot more.
|
40 |
|
41 | With SWR, components will get **a stream of data updates constantly and automatically**. Thus, the UI will be always **fast** and **reactive**.
|
42 |
|
43 | <br/>
|
44 |
|
45 | ## Quick Start
|
46 |
|
47 | ```js
|
48 | import useSWR from 'swr'
|
49 |
|
50 | function Profile () {
|
51 | const { data, error } = useSWR('/api/user', fetcher)
|
52 |
|
53 | if (error) return <div>failed to load</div>
|
54 | if (!data) return <div>loading...</div>
|
55 | return <div>hello {data.name}!</div>
|
56 | }
|
57 | ```
|
58 |
|
59 | In this example, the React Hook `useSWR` accepts a `key` and a `fetcher` function.
|
60 | `key` is a unique identifier of the request, normally the URL of the API. And the `fetcher` accepts
|
61 | `key` as its parameter and returns the data asynchronously.
|
62 |
|
63 | `useSWR` also returns 2 values: `data` and `error`. When the request (fetcher) is not yet finished,
|
64 | `data` will be `undefined`. And when we get a response, it sets `data` and `error` based on the result
|
65 | of `fetcher` and rerenders the component.
|
66 |
|
67 | Note that `fetcher` can be any asynchronous function, so you can use your favourite data-fetching
|
68 | library to handle that part.
|
69 |
|
70 | Check out [swr.now.sh](https://swr.now.sh) for more demos of SWR.
|
71 |
|
72 | <br/>
|
73 |
|
74 | ## Usage
|
75 |
|
76 | Inside your React project directory, run the following:
|
77 |
|
78 | ```
|
79 | yarn add swr
|
80 | ```
|
81 |
|
82 | Or with npm:
|
83 |
|
84 | ```
|
85 | npm install swr
|
86 | ```
|
87 |
|
88 | ### API
|
89 |
|
90 | ```js
|
91 | const { data, error, isValidating, revalidate } = useSWR(key, fetcher, options)
|
92 | ```
|
93 |
|
94 | #### Parameters
|
95 |
|
96 | - `key`: a unique key string for the request (or a function / array / null) [(advanced usage)](#conditional-fetching)
|
97 | - `fetcher`: (_optional_) a Promise returning function to fetch your data [(details)](#data-fetching)
|
98 | - `options`: (_optional_) an object of options for this SWR hook
|
99 |
|
100 | #### Return Values
|
101 | - `data`: data for the given key resolved by `fetcher` (or undefined if not loaded)
|
102 | - `error`: error thrown by `fetcher` (or undefined)
|
103 | - `isValidating`: if there's a request or revalidation loading
|
104 | - `revalidate`: function to trigger the validation manually
|
105 |
|
106 | #### Options
|
107 |
|
108 | - `suspense = false`: enable React Suspense mode [(details)](#suspense-mode)
|
109 | - `fetcher = undefined`: the default fetcher function
|
110 | - `revalidateOnFocus = true`: auto revalidate when window gets focused
|
111 | - `refreshInterval = 0`: polling interval (disabled by default)
|
112 | - `refreshWhenHidden = false`: polling when the window is invisible (if `refreshInterval` is enabled)
|
113 | - `shouldRetryOnError = true`: retry when fetcher has an error [(details)](#error-retries)
|
114 | - `dedupingInterval = 2000`: dedupe requests with the same key in this time span
|
115 | - `focusThrottleInterval = 5000`: only revalidate once during a time span
|
116 | - `loadingTimeout = 3000`: timeout to trigger the onLoadingSlow event
|
117 | - `errorRetryInterval = 5000`: error retry interval [(details)](#error-retries)
|
118 | - `onLoadingSlow`: callback function when a request takes too long to load (`loadingTimeout`)
|
119 | - `onSuccess`: callback function when a request finishs successfully
|
120 | - `onError`: callback function when a request returns an error
|
121 | - `onErrorRetry`: handler for [error retry](#error-retries)
|
122 | - `initialData`: initial data to be returned (note: This is per-hook)
|
123 |
|
124 | When under a slow network (2G, <= 70Kbps), `errorRetryInterval` will be 10s, and
|
125 | `loadingTimeout` will be 5s by default.
|
126 |
|
127 | You can also use [global configuration](#global-configuration) to provide default options.
|
128 |
|
129 | <br/>
|
130 |
|
131 | ## Examples
|
132 |
|
133 | - [Global Configuration](#global-configuration)
|
134 | - [Data Fetching](#data-fetching)
|
135 | - [Conditional Fetching](#conditional-fetching)
|
136 | - [Dependent Fetching](#dependent-fetching)
|
137 | - [Multiple Arguments](#multiple-arguments)
|
138 | - [Manually Revalidate](#manually-revalidate)
|
139 | - [Local Mutation](#local-mutation)
|
140 | - [Suspense Mode](#suspense-mode)
|
141 | - [Error Retries](#error-retries)
|
142 |
|
143 | ### Global Configuration
|
144 |
|
145 | The context `SWRConfig` can provide global configurations (`options`) for all SWR hooks.
|
146 |
|
147 | In this example, all SWRs will use the same fetcher provided to load JSON data, and refresh every 3 seconds by default:
|
148 |
|
149 | ```js
|
150 | import useSWR, { SWRConfig } from 'swr'
|
151 |
|
152 | function Dashboard () {
|
153 | const { data: events } = useSWR('/api/events')
|
154 | const { data: projects } = useSWR('/api/projects')
|
155 | const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // don't refresh
|
156 | // ...
|
157 | }
|
158 |
|
159 | function App () {
|
160 | return (
|
161 | <SWRConfig
|
162 | value={{
|
163 | refreshInterval: 3000,
|
164 | fetcher: (...args) => fetch(...args).then(res => res.json())
|
165 | }}
|
166 | >
|
167 | <Dashboard />
|
168 | </SWRConfig>
|
169 | )
|
170 | }
|
171 | ```
|
172 |
|
173 | ### Data Fetching
|
174 |
|
175 | `fetcher` is a function **accepts the `key`** of SWR, and returns a value or a Promise.
|
176 | You can use any library to handle data fetching, for example:
|
177 |
|
178 | ```js
|
179 | import fetch from 'unfetch'
|
180 |
|
181 | const fetcher = url => fetch(url).then(r => r.json())
|
182 |
|
183 | function App () {
|
184 | const { data } = useSWR('/api/data', fetcher)
|
185 | // ...
|
186 | }
|
187 | ```
|
188 |
|
189 | Or using GraphQL:
|
190 | ```js
|
191 | import { request } from 'graphql-request'
|
192 |
|
193 | const API = 'https://api.graph.cool/simple/v1/movies'
|
194 | const fetcher = query => request(API, query)
|
195 |
|
196 | function App () {
|
197 | const { data, error } = useSWR(
|
198 | `{
|
199 | Movie(title: "Inception") {
|
200 | releaseDate
|
201 | actors {
|
202 | name
|
203 | }
|
204 | }
|
205 | }`,
|
206 | fetcher
|
207 | )
|
208 | // ...
|
209 | }
|
210 | ```
|
211 |
|
212 | _If you want to pass variables to a GraphQL query, check out [Multiple Arguments](#multiple-arguments)._
|
213 |
|
214 | Note that `fetcher` can be skipped from the parameters if it's provided gloablly.
|
215 |
|
216 | ### Conditional Fetching
|
217 |
|
218 | Use `null` or pass a function as the `key` to `useSWR` to conditionally fetch data. If the functions throws an error or returns a falsy value, SWR will cancel the request.
|
219 |
|
220 | ```js
|
221 | // conditionally fetch
|
222 | const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
|
223 |
|
224 | // ...or return a falsy value
|
225 | const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
|
226 |
|
227 | // ... or throw an error when user.id is not defined
|
228 | const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
|
229 | ```
|
230 |
|
231 | ### Dependent Fetching
|
232 |
|
233 | SWR also allows you to fetch data that depends on other data. It ensures the maximum possible parallelism (avoiding waterfalls), as well as serial fetching when a piece of dynamic data is required for the next data fetch to happen.
|
234 |
|
235 | ```js
|
236 | function MyProjects () {
|
237 | const { data: user } = useSWR('/api/user')
|
238 | const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
|
239 | // When passing a function, SWR will use the
|
240 | // return value as `key`. If the function throws,
|
241 | // SWR will know that some dependencies are not
|
242 | // ready. In this case it is `user`.
|
243 |
|
244 | if (!projects) return 'loading...'
|
245 | return 'You have ' + projects.length + ' projects'
|
246 | }
|
247 | ```
|
248 |
|
249 | ### Multiple Arguments
|
250 |
|
251 | In some scenarios, it's useful pass multiple arguments (can be any value or object) to the `fetcher` function. For example:
|
252 |
|
253 | ```js
|
254 | const token = props.token
|
255 |
|
256 | useSWR('/api/data', url => fetchWithToken(url, token))
|
257 | ```
|
258 |
|
259 | **This is incorrect**. Because the identifier of the data is `'/api/data'`, which is also the index of the cache.
|
260 | When `token` changes, SWR will still treat it as the same key and request.
|
261 |
|
262 | Instead, you can use an array as the `key` parameter, which contains multiple arguments of `fetcher`:
|
263 |
|
264 | ```js
|
265 | useSWR(['/api/data', token], fetchWithToken)
|
266 | ```
|
267 |
|
268 | This solves the problem. The identifier of the request is now the combination of both values. SWR **shallowly** compares
|
269 | the arguments on every render, and triggers the validation if any of them has changed.
|
270 |
|
271 | ### Manually Revalidate
|
272 |
|
273 | You can broadcast a revalidation message globally to all SWRs with the same key by calling
|
274 | `trigger(key)`.
|
275 |
|
276 | This example shows how to automatically refetch the login info (e.g.: inside `<Profile/>`)
|
277 | when the user clicks the “Logout” button.
|
278 |
|
279 | ```js
|
280 | import useSWR, { trigger } from 'swr'
|
281 |
|
282 | function App () {
|
283 | return (
|
284 | <div>
|
285 | <Profile />
|
286 | <button onClick={() => {
|
287 | // set the cookie as expired
|
288 | document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
|
289 |
|
290 | // tell all SWRs with this key to revalidate
|
291 | trigger('/api/user')
|
292 | }}>
|
293 | Logout
|
294 | </button>
|
295 | </div>
|
296 | )
|
297 | }
|
298 | ```
|
299 |
|
300 | ### Local Mutation
|
301 |
|
302 | In many cases, applying local mutations to data is a good way to make changes
|
303 | feel faster — no need to wait for the remote source of data.
|
304 |
|
305 | With `mutate`, you can update your local data programmatically, while
|
306 | revalidating and finally replace it with the latest data.
|
307 |
|
308 | ```js
|
309 | import useSWR, { mutate } from 'swr'
|
310 |
|
311 | function Profile () {
|
312 | const { data } = useSWR('/api/user', fetcher)
|
313 |
|
314 | return (
|
315 | <div>
|
316 | <h1>My name is {data.name}.</h1>
|
317 | <button onClick={async () => {
|
318 | const newName = data.name.toUpperCase()
|
319 | // send a request to the API to update the data
|
320 | await requestUpdateUsername(newName)
|
321 | // update the local data immediately and revalidate (refetch)
|
322 | mutate('/api/user', { ...data, name: newName })
|
323 | }}>Uppercase my name!</button>
|
324 | </div>
|
325 | )
|
326 | }
|
327 | ```
|
328 |
|
329 | ### Suspense Mode
|
330 |
|
331 | You can enable the `suspense` option to use SWR with React Suspense:
|
332 |
|
333 | ```js
|
334 | import { Suspense } from 'react'
|
335 | import useSWR from 'swr'
|
336 |
|
337 | function Profile () {
|
338 | const { data } = useSWR('/api/user', fetcher, { suspense: true })
|
339 | return <div>hello, {data.name}</div>
|
340 | }
|
341 |
|
342 | function App () {
|
343 | return (
|
344 | <Suspense fallback={<div>loading...</div>}>
|
345 | <Profile/>
|
346 | </Suspense>
|
347 | )
|
348 | }
|
349 | ```
|
350 |
|
351 | Note in Suspense mode, `data` is always the fetch response (so you don't need to check if it's `undefined`). But if there's an error occurred, you need to use an [error boundary](https://reactjs.org/docs/concurrent-mode-suspense.html#handling-errors) to catch it.
|
352 |
|
353 | ### Error Retries
|
354 |
|
355 | By default, SWR uses the [exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff) to handle error retries.
|
356 | You can read more from the source code.
|
357 |
|
358 | It's also possible to override the behavior:
|
359 |
|
360 | ```js
|
361 | useSWR(key, fetcher, {
|
362 | onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
|
363 | if (retryCount >= 10) return
|
364 | if (error.status === 404) return
|
365 |
|
366 | // retry after 5 seconds
|
367 | setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
|
368 | }
|
369 | })
|
370 | ```
|
371 |
|
372 | <br/>
|
373 |
|
374 | ## Authors
|
375 | - Shu Ding ([@shuding_](https://twitter.com/shuding_)) – [ZEIT](https://zeit.co)
|
376 | - Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) – [ZEIT](https://zeit.co)
|
377 | - Joe Haddad ([@timer150](https://twitter.com/timer150)) - [ZEIT](https://zeit.co)
|
378 | - Paco Coursey ([@pacocoursey](https://twitter.com/pacocoursey)) - [ZEIT](https://zeit.co)
|
379 |
|
380 | Thanks to Ryan Chen for providing the awesome `swr` npm package name!
|
381 |
|
382 | <br/>
|
383 |
|
384 | ## License
|
385 | The MIT License.
|