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 | - Minimal API
|
37 |
|
38 | ...and a lot more.
|
39 |
|
40 | With SWR, components will get **a stream of data updates constantly and automatically**. Thus, the UI will be always **fast** and **reactive**.
|
41 |
|
42 | ## Quick Start
|
43 |
|
44 | ```js
|
45 | import useSWR from 'swr'
|
46 |
|
47 | function Profile () {
|
48 | const { data, error } = useSWR('/api/user', fetcher)
|
49 |
|
50 | if (error) return <div>failed to load</div>
|
51 | if (!data) return <div>loading...</div>
|
52 | return <div>hello {data.name}!</div>
|
53 | }
|
54 | ```
|
55 |
|
56 | In this example, the React Hook `useSWR` accepts a `key` and a `fetcher` function.
|
57 | `key` is a unique identifier of the request, normally the URL of the API. And the `fetcher` accepts
|
58 | `key` as its parameter and returns the data asynchronously.
|
59 |
|
60 | `useSWR` also returns 2 values: `data` and `error`. When the request (fetcher) is not yet finished,
|
61 | `data` will be `undefined`. And when we get a response, it sets `data` and `error` based on the result
|
62 | of `fetcher` and rerenders the component.
|
63 |
|
64 | Note that `fetcher` can be any asynchronous function, so you can use your favourite data-fetching
|
65 | library to handle that part.
|
66 |
|
67 | Check out [swr.now.sh](https://swr.now.sh) for more demos of SWR.
|
68 |
|
69 | ## Usage
|
70 |
|
71 | Inside your React project directory, run the following:
|
72 |
|
73 | ```
|
74 | yarn add swr
|
75 | ```
|
76 |
|
77 | Or with npm:
|
78 |
|
79 | ```
|
80 | npm install swr
|
81 | ```
|
82 |
|
83 | ### API
|
84 |
|
85 | ```js
|
86 | const { data, error, isValidating, revalidate } = useSWR(key, fetcher, options)
|
87 | ```
|
88 |
|
89 | #### Parameters
|
90 |
|
91 | - `key`: a unique key string for the request (or a function / null) [(advanced usage)](#conditional-fetching)
|
92 | - `fetcher`: (_optional_) a Promise returning function to fetch your data [(details)](#data-fetching)
|
93 | - `options`: (_optional_) an object of options for this SWR hook
|
94 |
|
95 | #### Return Values
|
96 | - `data`: data for the given key resolved by `fetcher` (or undefined if not loaded)
|
97 | - `error`: error thrown by `fetcher` (or undefined)
|
98 | - `isValidating`: if there's a request or revalidation loading
|
99 | - `revalidate`: function to trigger the validation manually
|
100 |
|
101 | #### Options
|
102 |
|
103 | - `suspense = false`: enable React Suspense mode [(details)](#suspense-mode)
|
104 | - `fetcher = undefined`: the default fetcher function
|
105 | - `revalidateOnFocus = true`: auto revalidate when window gets focused
|
106 | - `refreshInterval = 0`: polling interval (disabled by default)
|
107 | - `refreshWhenHidden = false`: polling when the window is invisible (if `refreshInterval` is enabled)
|
108 | - `shouldRetryOnError = true`: retry when fetcher has an error [(details)](#error-retries)
|
109 | - `dedupingInterval = 2000`: dedupe requests with the same key in this time span
|
110 | - `focusThrottleInterval = 5000`: only revalidate once during a time span
|
111 | - `loadingTimeout = 3000`: timeout to trigger the onLoadingSlow event
|
112 | - `errorRetryInterval = 5000`: error retry interval [(details)](#error-retries)
|
113 | - `onLoadingSlow`: callback function when a request takes too long to load (`loadingTimeout`)
|
114 | - `onSuccess`: callback function when a request finishs successfully
|
115 | - `onError`: callback function when a request returns an error
|
116 | - `onErrorRetry`: handler for [error retry](#error-retries)
|
117 |
|
118 | When under a slow network (2G, <= 70Kbps), `errorRetryInterval` will be 10s, and
|
119 | `loadingTimeout` will be 5s by default.
|
120 |
|
121 | You can also use [global configuration](#global-configuration) to provide default options.
|
122 |
|
123 | ## Examples
|
124 |
|
125 | - [Global Configuration](#global-configuration)
|
126 | - [Data Fetching](#data-fetching)
|
127 | - [Conditional Fetching](#conditional-fetching)
|
128 | - [Dependent Fetching](#dependent-fetching)
|
129 | - [Manually Revalidate](#manually-revalidate)
|
130 | - [Local Mutation](#local-mutation)
|
131 | - [Suspense Mode](#suspense-mode)
|
132 | - [Error Retries](#error-retries)
|
133 |
|
134 | ### Global Configuration
|
135 |
|
136 | You can use `SWRConfig` to provide global configurations (`options`) for all SWR hooks.
|
137 |
|
138 | In this example, all `useSWR` hooks will use the same fetcher provided to load JSON data, and refresh every 3 seconds (except the user API):
|
139 |
|
140 | ```js
|
141 | import useSWR, { SWRConfig } from 'swr'
|
142 |
|
143 | function Dashboard () {
|
144 | const { data: events } = useSWR('/api/events')
|
145 | const { data: projects } = useSWR('/api/projects')
|
146 | const { data: user } = useSWR('/api/user', { refreshInterval: 0 })
|
147 | // ...
|
148 | }
|
149 |
|
150 | function App () {
|
151 | return (
|
152 | <SWRConfig
|
153 | value={{
|
154 | refreshInterval: 3000,
|
155 | fetcher: (...args) => fetch(...args).then(res => res.json())
|
156 | }}
|
157 | >
|
158 | <Dashboard />
|
159 | </SWRConfig>
|
160 | )
|
161 | }
|
162 | ```
|
163 |
|
164 | ### Data Fetching
|
165 |
|
166 | `fetcher` is a function **accepts the `key`** of SWR, and returns a value or a Promise.
|
167 | You can use any library you to handle data fetching, for example:
|
168 |
|
169 | ```js
|
170 | import fetch from 'unfetch'
|
171 |
|
172 | const fetcher = url => fetch(url).then(r => r.json())
|
173 |
|
174 | function App () {
|
175 | const { data } = useSWR('/api/data', fetcher)
|
176 | // ...
|
177 | }
|
178 | ```
|
179 |
|
180 | Or using GraphQL:
|
181 | ```js
|
182 | import { request } from 'graphql-request'
|
183 |
|
184 | const API = 'https://api.graph.cool/simple/v1/movies'
|
185 | const fetcher = query => request(API, query)
|
186 |
|
187 | function App () {
|
188 | const { data, error } = useSWR(
|
189 | `{
|
190 | Movie(title: "Inception") {
|
191 | releaseDate
|
192 | actors {
|
193 | name
|
194 | }
|
195 | }
|
196 | }`,
|
197 | fetcher
|
198 | )
|
199 | // ...
|
200 | }
|
201 | ```
|
202 |
|
203 | Note that `fetcher` can be skipped from the parameters if it's provided gloablly.
|
204 |
|
205 | ### Conditional Fetching
|
206 |
|
207 | 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.
|
208 |
|
209 | ```js
|
210 | // conditionally fetch
|
211 | const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
|
212 |
|
213 | // ...or return a falsy value
|
214 | const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
|
215 |
|
216 | // ... or throw an error when user.id is not defined
|
217 | const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
|
218 | ```
|
219 |
|
220 | ### Dependent Fetching
|
221 |
|
222 | 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.
|
223 |
|
224 | ```js
|
225 | function MyProjects () {
|
226 | const { data: user } = useSWR('/api/user')
|
227 | const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
|
228 | // When passing a function, SWR will use the
|
229 | // return value as `key`. If the function throws,
|
230 | // SWR will know that some dependencies are not
|
231 | // ready. In this case it is `user`.
|
232 |
|
233 | if (!projects) return 'loading...'
|
234 | return 'You have ' + projects.length + ' projects'
|
235 | }
|
236 | ```
|
237 |
|
238 | ### Manually Revalidate
|
239 |
|
240 | You can broadcast a revalidation message to all SWR data inside any component by calling
|
241 | `trigger(key)`.
|
242 |
|
243 | This example shows how to automatically refetch the login info (e.g.: inside `<Profile/>`)
|
244 | when the user clicks the “Logout” button.
|
245 |
|
246 | ```js
|
247 | import useSWR, { trigger } from 'swr'
|
248 |
|
249 | function App () {
|
250 | return (
|
251 | <div>
|
252 | <Profile />
|
253 | <button onClick={() => {
|
254 | // set the cookie as expired
|
255 | document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
|
256 |
|
257 | // tell all SWRs with this key to revalidate
|
258 | trigger('/api/user')
|
259 | }}>
|
260 | Logout
|
261 | </button>
|
262 | </div>
|
263 | )
|
264 | }
|
265 | ```
|
266 |
|
267 | ### Local Mutation
|
268 |
|
269 | In many cases, applying local mutations to data is a good way to make changes
|
270 | feel faster — no need to wait for the remote source of data.
|
271 |
|
272 | With `mutate`, you can update your local data programmatically, while
|
273 | revalidating and finally replace it with the latest data.
|
274 |
|
275 | ```js
|
276 | import useSWR, { mutate } from 'swr'
|
277 |
|
278 | function Profile () {
|
279 | const { data } = useSWR('/api/user', fetcher)
|
280 |
|
281 | return (
|
282 | <div>
|
283 | <h1>My name is {data.name}.</h1>
|
284 | <button onClick={async () => {
|
285 | const newName = data.name.toUpperCase()
|
286 | // send a request to the API to update the data
|
287 | await requestUpdateUsername(newName)
|
288 | // update the local data immediately and revalidate (refetch)
|
289 | mutate('/api/user', { ...data, name: newName })
|
290 | }}>Uppercase my name!</button>
|
291 | </div>
|
292 | )
|
293 | }
|
294 | ```
|
295 |
|
296 | ### Suspense Mode
|
297 |
|
298 | You can enable the `suspense` option to use SWR with React Suspense:
|
299 |
|
300 | ```js
|
301 | import { Suspense } from 'react'
|
302 | import useSWR from 'swr'
|
303 |
|
304 | function Profile () {
|
305 | const { data } = useSWR('/api/user', fetcher, { suspense: true })
|
306 | return <div>hello, {data.name}</div>
|
307 | }
|
308 |
|
309 | function App () {
|
310 | return (
|
311 | <Suspense fallback={<div>loading...</div>}>
|
312 | <Profile/>
|
313 | </Suspense>
|
314 | )
|
315 | }
|
316 | ```
|
317 |
|
318 | 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.
|
319 |
|
320 | ### Error Retries
|
321 |
|
322 | By default, SWR uses the [exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff) to handle error retries.
|
323 | You can read more from the source code.
|
324 |
|
325 | It's also possible to override the behavior:
|
326 |
|
327 | ```js
|
328 | useSWR(key, fetcher, {
|
329 | onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
|
330 | if (retryCount >= 10) return
|
331 | if (error.status === 404) return
|
332 |
|
333 | // retry after 5 seconds
|
334 | setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
|
335 | }
|
336 | })
|
337 | ```
|
338 |
|
339 | ## Authors
|
340 | - Shu Ding ([@shuding_](https://twitter.com/shuding_)) – [ZEIT](https://zeit.co)
|
341 | - Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) – [ZEIT](https://zeit.co)
|
342 | - Joe Haddad ([@timer150](https://twitter.com/timer150)) - [ZEIT](https://zeit.co)
|
343 | - Paco Coursey ([@pacocoursey](https://twitter.com/pacocoursey)) - [ZEIT](https://zeit.co)
|
344 |
|
345 | Thanks to Ryan Chen for providing the awesome `swr` npm package name!
|
346 |
|
347 | ## License
|
348 | The MIT License.
|