UNPKG

16.5 kBMarkdownView Raw
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://badgen.net/badge/icon/MADE%20BY%20ZEIT?icon=zeit&label&color=black&labelColor=black">
6 </a>
7 <a aria-label="NPM version" href="https://www.npmjs.com/package/swr">
8 <img alt="" src="https://badgen.net/npm/v/swr">
9 </a>
10 <a aria-label="Package size" href="https://bundlephobia.com/result?p=swr">
11 <img alt="" src="https://badgen.net/bundlephobia/minzip/swr">
12 </a>
13 <a aria-label="License" href="https://github.com/zeit/swr/blob/master/LICENSE">
14 <img alt="" src="https://badgen.net/npm/license/swr">
15 </a>
16</p>
17
18## Introduction
19
20[swr.now.sh](https://swr.now.sh)
21
22SWR is a React Hooks library for remote data fetching.
23
24The name “**SWR**” is derived from `stale-while-revalidate`, a cache invalidation strategy popularized by [HTTP 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
27It features:
28- Transport and protocol agnostic data fetching
29- Fast page navigation
30- Revalidation on focus
31- Interval polling
32- Request deduplication
33- Local mutation
34- Pagination
35- TypeScript ready
36- SSR support
37- Suspense mode
38- React Native support
39- Minimal API
40
41...and a lot more.
42
43With SWR, components will get **a stream of data updates constantly and automatically**. Thus, the UI will be always **fast** and **reactive**.
44
45<br/>
46
47## Quick Start
48
49```js
50import useSWR from 'swr'
51
52function Profile () {
53 const { data, error } = useSWR('/api/user', fetcher)
54
55 if (error) return <div>failed to load</div>
56 if (!data) return <div>loading...</div>
57 return <div>hello {data.name}!</div>
58}
59```
60
61In this example, the React Hook `useSWR` accepts a `key` and a `fetcher` function.
62`key` is a unique identifier of the request, normally the URL of the API. And the `fetcher` accepts
63`key` as its parameter and returns the data asynchronously.
64
65`useSWR` also returns 2 values: `data` and `error`. When the request (fetcher) is not yet finished,
66`data` will be `undefined`. And when we get a response, it sets `data` and `error` based on the result
67of `fetcher` and rerenders the component.
68
69Note that `fetcher` can be any asynchronous function, so you can use your favourite data-fetching
70library to handle that part.
71
72Check out [swr.now.sh](https://swr.now.sh) for more demos of SWR, and [Examples](#examples) for the best practices.
73
74<br/>
75
76## Usage
77
78Inside your React project directory, run the following:
79
80```
81yarn add swr
82```
83
84Or with npm:
85
86```
87npm install swr
88```
89
90### API
91
92```js
93const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)
94```
95
96#### Parameters
97
98- `key`: a unique key string for the request (or a function / array / null) [(advanced usage)](#conditional-fetching)
99- `fetcher`: (_optional_) a Promise returning function to fetch your data [(details)](#data-fetching)
100- `options`: (_optional_) an object of options for this SWR hook
101
102#### Return Values
103- `data`: data for the given key resolved by `fetcher` (or undefined if not loaded)
104- `error`: error thrown by `fetcher` (or undefined)
105- `isValidating`: if there's a request or revalidation loading
106- `mutate`: function to mutate the cached data
107
108#### Options
109
110- `suspense = false`: enable React Suspense mode [(details)](#suspense-mode)
111- `fetcher = undefined`: the default fetcher function
112- `initialData`: initial data to be returned (note: This is per-hook)
113- `revalidateOnFocus = true`: auto revalidate when window gets focused
114- `revalidateOnReconnect = true`: automatically revalidate when the browser regains a network connection (via `navigator.onLine`)
115- `refreshInterval = 0`: polling interval (disabled by default)
116- `refreshWhenHidden = false`: polling when the window is invisible (if `refreshInterval` is enabled)
117- `refreshWhenOffline = false`: polling when the browser is offline (determined by `navigator.onLine`)
118- `shouldRetryOnError = true`: retry when fetcher has an error [(details)](#error-retries)
119- `dedupingInterval = 2000`: dedupe requests with the same key in this time span
120- `focusThrottleInterval = 5000`: only revalidate once during a time span
121- `loadingTimeout = 3000`: timeout to trigger the onLoadingSlow event
122- `errorRetryInterval = 5000`: error retry interval [(details)](#error-retries)
123- `errorRetryCount`: max error retry count [(details)](#error-retries)
124- `onLoadingSlow`: callback function when a request takes too long to load (see `loadingTimeout`)
125- `onSuccess`: callback function when a request finishes successfully
126- `onError`: callback function when a request returns an error
127- `onErrorRetry`: handler for [error retry](#error-retries)
128- `compare`: comparison function used to detect when returned data has changed, to avoid spurious rerenders. By default, [fast-deep-equal](https://github.com/epoberezkin/fast-deep-equal) is used.
129
130When under a slow network (2G, <= 70Kbps), `errorRetryInterval` will be 10s, and
131`loadingTimeout` will be 5s by default.
132
133You can also use [global configuration](#global-configuration) to provide default options.
134
135<br/>
136
137## Examples
138
139- [Global Configuration](#global-configuration)
140- [Data Fetching](#data-fetching)
141- [Conditional Fetching](#conditional-fetching)
142- [Dependent Fetching](#dependent-fetching)
143- [Multiple Arguments](#multiple-arguments)
144- [Manually Revalidate](#manually-revalidate)
145- [Mutation and Post Request](#mutation-and-post-request)
146- [Mutate Based on Current Data](#mutate-based-on-current-data)
147- [Returned Data from Mutate](#returned-data-from-mutate)
148- [SSR with Next.js](#ssr-with-nextjs)
149- [Suspense Mode](#suspense-mode)
150- [Error Retries](#error-retries)
151- [Prefetching Data](#prefetching-data)
152
153### Global Configuration
154
155The context `SWRConfig` can provide global configurations (`options`) for all SWR hooks.
156
157In this example, all SWRs will use the same fetcher provided to load JSON data, and refresh every 3 seconds by default:
158
159```js
160import useSWR, { SWRConfig } from 'swr'
161
162function Dashboard () {
163 const { data: events } = useSWR('/api/events')
164 const { data: projects } = useSWR('/api/projects')
165 const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // don't refresh
166 // ...
167}
168
169function App () {
170 return (
171 <SWRConfig
172 value={{
173 refreshInterval: 3000,
174 fetcher: (...args) => fetch(...args).then(res => res.json())
175 }}
176 >
177 <Dashboard />
178 </SWRConfig>
179 )
180}
181```
182
183### Data Fetching
184
185`fetcher` is a function that **accepts the `key`** of SWR, and returns a value or a Promise.
186You can use any library to handle data fetching, for example:
187
188```js
189import fetch from 'unfetch'
190
191const fetcher = url => fetch(url).then(r => r.json())
192
193function App () {
194 const { data } = useSWR('/api/data', fetcher)
195 // ...
196}
197```
198
199Or using GraphQL:
200```js
201import { request } from 'graphql-request'
202
203const API = 'https://api.graph.cool/simple/v1/movies'
204const fetcher = query => request(API, query)
205
206function App () {
207 const { data, error } = useSWR(
208 `{
209 Movie(title: "Inception") {
210 releaseDate
211 actors {
212 name
213 }
214 }
215 }`,
216 fetcher
217 )
218 // ...
219}
220```
221
222_If you want to pass variables to a GraphQL query, check out [Multiple Arguments](#multiple-arguments)._
223
224Note that `fetcher` can be omitted from the parameters if it's provided globally.
225
226### Conditional Fetching
227
228Use `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.
229
230```js
231// conditionally fetch
232const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
233
234// ...or return a falsy value
235const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
236
237// ... or throw an error when user.id is not defined
238const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
239```
240
241### Dependent Fetching
242
243SWR 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.
244
245```js
246function MyProjects () {
247 const { data: user } = useSWR('/api/user')
248 const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
249 // When passing a function, SWR will use the
250 // return value as `key`. If the function throws,
251 // SWR will know that some dependencies are not
252 // ready. In this case it is `user`.
253
254 if (!projects) return 'loading...'
255 return 'You have ' + projects.length + ' projects'
256}
257```
258
259### Multiple Arguments
260
261In some scenarios, it's useful pass multiple arguments (can be any value or object) to the `fetcher` function. For example:
262
263```js
264useSWR('/api/user', url => fetchWithToken(url, token))
265```
266
267This is **incorrect**. Because the identifier (also the index of the cache) of the data is `'/api/data'`,
268so even if `token` changes, SWR will still have the same key and return the wrong data.
269
270Instead, you can use an **array** as the `key` parameter, which contains multiple arguments of `fetcher`:
271
272```js
273const { data: user } = useSWR(['/api/user', token], fetchWithToken)
274
275// ...and pass it as an argument to another query
276const { data: orders } = useSWR(user ? ['/api/orders', user] : null, fetchWithUser)
277```
278
279The key of the request is now the combination of both values. SWR **shallowly** compares
280the arguments on every render, and triggers revalidation if any of them has changed.
281Keep in mind that you should not recreate objects when rendering, as they will be treated as different objects on every render:
282
283```js
284// Don’t do this! Deps will be changed on every render.
285useSWR(['/api/user', { id }], query)
286
287// Instead, you should only pass “stable” values.
288useSWR(['/api/user', id], (url, id) => query(url, { id }))
289```
290
291Dan Abramov explains dependencies very well in [this blog post](https://overreacted.io/a-complete-guide-to-useeffect/#but-i-cant-put-this-function-inside-an-effect).
292
293### Manually Revalidate
294
295You can broadcast a revalidation message globally to all SWRs with the same key by calling
296`mutate(key)`.
297
298This example shows how to automatically refetch the login info (e.g.: inside `<Profile/>`)
299when the user clicks the “Logout” button.
300
301```js
302import useSWR, { mutate } from 'swr'
303
304function App () {
305 return (
306 <div>
307 <Profile />
308 <button onClick={() => {
309 // set the cookie as expired
310 document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
311
312 // tell all SWRs with this key to revalidate
313 mutate('/api/user')
314 }}>
315 Logout
316 </button>
317 </div>
318 )
319}
320```
321
322### Mutation and Post Request
323
324In many cases, applying local mutations to data is a good way to make changes
325feel faster — no need to wait for the remote source of data.
326
327With `mutate`, you can update your local data programmatically, while
328revalidating and finally replace it with the latest data.
329
330```js
331import useSWR, { mutate } from 'swr'
332
333function Profile () {
334 const { data } = useSWR('/api/user', fetcher)
335
336 return (
337 <div>
338 <h1>My name is {data.name}.</h1>
339 <button onClick={async () => {
340 const newName = data.name.toUpperCase()
341 // send a request to the API to update the data
342 await requestUpdateUsername(newName)
343 // update the local data immediately and revalidate (refetch)
344 mutate('/api/user', { ...data, name: newName })
345 }}>Uppercase my name!</button>
346 </div>
347 )
348}
349```
350
351Clicking the button in the example above will send a POST request to modify the remote data, locally update the client data and
352try to fetch the latest one (revalidate).
353
354But many POST APIs will just return the updated data directly, so we don’t need to revalidate again.
355Here’s an example showing the “local mutate - request - update” usage:
356
357```js
358mutate('/api/user', newUser, false) // use `false` to mutate without revalidation
359mutate('/api/user', updateUser(newUser)) // `updateUser` is a Promise of the request,
360 // which returns the updated document
361```
362
363### Mutate Based on Current Data
364
365In many cases, you are receiving a single value back from your API and want to update a list of them.
366
367With `mutate`, you can pass an async function which will receive the current cached value, if any, and let you return an updated document.
368
369```js
370mutate('/api/users', async users => {
371 const user = await fetcher('/api/users/1')
372 return [user, ...users.slice(1)]
373})
374```
375
376### Returned Data from Mutate
377
378Most probably, you need to data mutate used to update the cache when you passed a promise or async function.
379
380The function will returns the updated document, or throw an error, everytime you call it.
381
382```js
383try {
384 const user = await mutate('/api/user', updateUser(newUser))
385} catch (error) {
386 // Handle an error while updating the user here
387}
388```
389
390### SSR with Next.js
391
392With the `initialData` option, you pass an initial value to the hook. It works perfectly with many SSR solutions
393such as `getServerSideProps` in [Next.js](https://github.com/zeit/next.js):
394
395```js
396export async function getServerSideProps() {
397 const data = await fetcher('/api/data')
398 return { props: { data } }
399}
400
401function App (props) {
402 const initialData = props.data
403 const { data } = useSWR('/api/data', fetcher, { initialData })
404
405 return <div>{data}</div>
406}
407```
408
409It is still a server-side rendered site, but it’s also fully powered by SWR in the client side.
410Which means the data can be dynamic and update itself over time and user interactions.
411
412### Suspense Mode
413
414You can enable the `suspense` option to use SWR with React Suspense:
415
416```js
417import { Suspense } from 'react'
418import useSWR from 'swr'
419
420function Profile () {
421 const { data } = useSWR('/api/user', fetcher, { suspense: true })
422 return <div>hello, {data.name}</div>
423}
424
425function App () {
426 return (
427 <Suspense fallback={<div>loading...</div>}>
428 <Profile/>
429 </Suspense>
430 )
431}
432```
433
434In Suspense mode, `data` is always the fetch response (so you don't need to check if it's `undefined`).
435But if an error occurred, you need to use an [error boundary](https://reactjs.org/docs/concurrent-mode-suspense.html#handling-errors) to catch it.
436
437_Note that Suspense is not supported in SSR mode._
438
439### Error Retries
440
441By default, SWR uses the [exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff) to handle error retries.
442You can read more from the source code.
443
444It's also possible to override the behavior:
445
446```js
447useSWR(key, fetcher, {
448 onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
449 if (retryCount >= 10) return
450 if (error.status === 404) return
451
452 // retry after 5 seconds
453 setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
454 }
455})
456```
457
458### Prefetching Data
459
460There’re many ways to prefetch the data for SWR. For top level requests, [`rel="preload"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content) is highly recommended:
461
462```html
463<link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">
464```
465
466This will prefetch the data before the JavaScript starts downloading. And your incoming fetch requests will reuse the result (including SWR, of course).
467
468Another choice is to prefetch the data conditionally. You can have a function to refetch and set the cache:
469
470```js
471function prefetch () {
472 mutate('/api/data', fetch('/api/data').then(res => res.json()))
473 // the second parameter is a Promise
474 // SWR will use the result when it resolves
475}
476```
477
478And use it when you need to preload the **resources** (for example when [hovering](https://github.com/GoogleChromeLabs/quicklink) [a](https://github.com/guess-js/guess) [link](https://instant.page)).
479Together with techniques like [page prefetching](https://nextjs.org/docs#prefetching-pages) in Next.js, you will be able to load both next page and data instantly.
480
481<br/>
482
483## Authors
484- Shu Ding ([@shuding_](https://twitter.com/shuding_)) – [ZEIT](https://zeit.co)
485- Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) – [ZEIT](https://zeit.co)
486- Joe Haddad ([@timer150](https://twitter.com/timer150)) - [ZEIT](https://zeit.co)
487- Paco Coursey ([@pacocoursey](https://twitter.com/pacocoursey)) - [ZEIT](https://zeit.co)
488
489Thanks to Ryan Chen for providing the awesome `swr` npm package name!
490
491<br/>
492
493## License
494The MIT License.