UNPKG

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