UNPKG

11.9 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://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
22SWR is a React Hooks library for remote data fetching.
23
24The 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
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- Suspense mode
36- React Native support
37- Minimal API
38
39...and a lot more.
40
41With 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
48import useSWR from 'swr'
49
50function 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
59In 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
65of `fetcher` and rerenders the component.
66
67Note that `fetcher` can be any asynchronous function, so you can use your favourite data-fetching
68library to handle that part.
69
70Check out [swr.now.sh](https://swr.now.sh) for more demos of SWR.
71
72<br/>
73
74## Usage
75
76Inside your React project directory, run the following:
77
78```
79yarn add swr
80```
81
82Or with npm:
83
84```
85npm install swr
86```
87
88### API
89
90```js
91const { 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
124When under a slow network (2G, <= 70Kbps), `errorRetryInterval` will be 10s, and
125`loadingTimeout` will be 5s by default.
126
127You 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
145The context `SWRConfig` can provide global configurations (`options`) for all SWR hooks.
146
147In this example, all SWRs will use the same fetcher provided to load JSON data, and refresh every 3 seconds by default:
148
149```js
150import useSWR, { SWRConfig } from 'swr'
151
152function 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
159function 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.
176You can use any library to handle data fetching, for example:
177
178```js
179import fetch from 'unfetch'
180
181const fetcher = url => fetch(url).then(r => r.json())
182
183function App () {
184 const { data } = useSWR('/api/data', fetcher)
185 // ...
186}
187```
188
189Or using GraphQL:
190```js
191import { request } from 'graphql-request'
192
193const API = 'https://api.graph.cool/simple/v1/movies'
194const fetcher = query => request(API, query)
195
196function 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
214Note that `fetcher` can be skipped from the parameters if it's provided gloablly.
215
216### Conditional Fetching
217
218Use `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
222const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
223
224// ...or return a falsy value
225const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
226
227// ... or throw an error when user.id is not defined
228const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
229```
230
231### Dependent Fetching
232
233SWR 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
236function 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
251In some scenarios, it's useful pass multiple arguments (can be any value or object) to the `fetcher` function. For example:
252
253```js
254const token = props.token
255
256useSWR('/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.
260When `token` changes, SWR will still treat it as the same key and request.
261
262Instead, you can use an array as the `key` parameter, which contains multiple arguments of `fetcher`:
263
264```js
265useSWR(['/api/data', token], fetchWithToken)
266```
267
268This solves the problem. The identifier of the request is now the combination of both values. SWR **shallowly** compares
269the arguments on every render, and triggers the validation if any of them has changed.
270
271### Manually Revalidate
272
273You can broadcast a revalidation message globally to all SWRs with the same key by calling
274`trigger(key)`.
275
276This example shows how to automatically refetch the login info (e.g.: inside `<Profile/>`)
277when the user clicks the “Logout” button.
278
279```js
280import useSWR, { trigger } from 'swr'
281
282function 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
302In many cases, applying local mutations to data is a good way to make changes
303feel faster — no need to wait for the remote source of data.
304
305With `mutate`, you can update your local data programmatically, while
306revalidating and finally replace it with the latest data.
307
308```js
309import useSWR, { mutate } from 'swr'
310
311function 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
331You can enable the `suspense` option to use SWR with React Suspense:
332
333```js
334import { Suspense } from 'react'
335import useSWR from 'swr'
336
337function Profile () {
338 const { data } = useSWR('/api/user', fetcher, { suspense: true })
339 return <div>hello, {data.name}</div>
340}
341
342function App () {
343 return (
344 <Suspense fallback={<div>loading...</div>}>
345 <Profile/>
346 </Suspense>
347 )
348}
349```
350
351Note 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
355By default, SWR uses the [exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff) to handle error retries.
356You can read more from the source code.
357
358It's also possible to override the behavior:
359
360```js
361useSWR(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
380Thanks to Ryan Chen for providing the awesome `swr` npm package name!
381
382<br/>
383
384## License
385The MIT License.