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="SWR website" href="https://swr.now.sh">swr.now.sh<a>
|
5 | </p>
|
6 |
|
7 | <p align="center">
|
8 | <a aria-label="ZEIT logo" href="https://github.com/zeit">
|
9 | <img src="https://img.shields.io/badge/MADE%20BY%20ZEIT-000000.svg?logo=ZEIT&labelColor=000000&logoWidth=12">
|
10 | </a>
|
11 | <a aria-label="NPM version" href="https://www.npmjs.com/package/swr">
|
12 | <img alt="" src="https://img.shields.io/npm/v/swr">
|
13 | </a>
|
14 | <a aria-label="Package size" href="https://bundlephobia.com/result?p=swr">
|
15 | <img alt="" src="https://img.shields.io/bundlephobia/minzip/swr">
|
16 | </a>
|
17 | <a aria-label="License" href="https://github.com/zeit/swr/blob/master/LICENSE">
|
18 | <img alt="" src="https://img.shields.io/npm/l/swr">
|
19 | </a>
|
20 | </p>
|
21 |
|
22 | ## Intro
|
23 |
|
24 | SWR is a React Hooks library for remote data fetching.
|
25 |
|
26 | The name “**SWR**” is derived from `stale-while-revalidate`, a HTTP cache invalidation strategy popularized by [RFC 5861](https://tools.ietf.org/html/rfc5861).
|
27 | **SWR** first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.
|
28 |
|
29 | It features:
|
30 | - Transport and protocol agnostic data fetching
|
31 | - Fast page navigation
|
32 | - Revalidation on focus
|
33 | - Interval polling
|
34 | - Local mutation
|
35 | - Pagination
|
36 | - TypeScript ready
|
37 | - Suspense mode
|
38 | - Minimal API
|
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 | To install, run `yarn add swr` or `npm install swr` in your React project.
|
45 |
|
46 | ```js
|
47 | import useSWR from 'swr'
|
48 |
|
49 | function Profile () {
|
50 | const { data, error } = useSWR('/api/user', fetcher)
|
51 |
|
52 | if (error) return <div>failed to load</div>
|
53 | if (!data) return <div>loading...</div>
|
54 | return <div>hello {data.name}!</div>
|
55 | }
|
56 | ```
|
57 |
|
58 | In this example, the React Hook `useSWR` accepts a `key` and a `fetcher` function.
|
59 | `key` is a unique identifier of the data, normally a URL of the API. And the `fetcher` accepts
|
60 | `key` as its parameter and returns the data asynchronously.
|
61 |
|
62 | `useSWR` also returns 2 values: `data` and `error`. When the request (fetcher) is not yet finished,
|
63 | `data` will be `undefined`. And when we get a response, it sets `data` and `error` based on the result
|
64 | of `fetcher` and rerenders the component.
|
65 |
|
66 | Note that `fetcher` can be any asynchronous function, so you can use your favourite data-fetching
|
67 | library to handle that part.
|
68 |
|
69 | ---
|
70 |
|
71 | - API
|
72 | - [`useSWR`](#useswr)
|
73 | - [`SWRConfig`](#swrconfig)
|
74 | - [`mutate`](#mutate)
|
75 | - [`trigger`](#trigger)
|
76 | - Examples
|
77 | - [Suspense Mode](#suspense-mode)
|
78 | - [Subscription (e.g.: socket.io)](#subscription-eg-socketio)
|
79 | - [Dependent Fetching](#dependent-fetching)
|
80 |
|
81 | ## API
|
82 |
|
83 | ### `useSWR`
|
84 |
|
85 | ```js
|
86 | const {
|
87 | data, // data for the given key (or undefined)
|
88 | error, // error (or undefined)
|
89 | isValidating, // if the request is loading
|
90 | revalidate // function to trigger a validate manually
|
91 | } = useSWR(
|
92 | key, // a unique key for the data (or a function, see below)
|
93 | fetcher, // Promise returning function to load your data
|
94 | swrOptions? = {
|
95 | suspense: false, // enabled React Suspense mode
|
96 | revalidateOnFocus: true, // auto revalidate when window gets focused
|
97 | refreshWhenHidden: false, // refresh while the window is invisible
|
98 | shouldRetryOnError: true, // retry when fetcher has an error
|
99 | refreshInterval: 0, // polling interval (disabled by default)
|
100 | errorRetryInterval: 5000, // error retry interval (10s on slow network)
|
101 | focusThrottleInterval: 5000, // keep focus revalidate requests in a time window
|
102 | dedupingInterval: 2000, // deduping requests
|
103 | loadingTimeout: 3000, // timeout for triggering the onLoadingSlow event
|
104 |
|
105 | onLoadingSlow, // event handlers
|
106 | onSuccess,
|
107 | onError,
|
108 | onErrorRetry,
|
109 |
|
110 | fetcher // default fetcher function
|
111 | }
|
112 | )
|
113 | ```
|
114 |
|
115 | #### `key` as a function
|
116 |
|
117 | 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.
|
118 |
|
119 | ```js
|
120 | // key returns a falsy value
|
121 | const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
|
122 |
|
123 | // key throws an error when user.id is not defined
|
124 | const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
|
125 | ```
|
126 |
|
127 | ### `SWRConfig`
|
128 |
|
129 | A context to provide global configurations (`swrOptions`) for SWR.
|
130 |
|
131 | ```js
|
132 | import useSWR, { SWRConfig } from 'swr'
|
133 |
|
134 | function App () {
|
135 | // all the SWRs inside will use `refreshInterval: 1000`
|
136 | // and the native `fetch` implementation
|
137 | return <SWRConfig value={{
|
138 | refreshInterval: 1000,
|
139 | fetcher: (...args) => fetch(...args).then(res => res.json())
|
140 | }}>
|
141 | <Profile/>
|
142 | </SWRConfig>
|
143 | }
|
144 |
|
145 | function Profile () {
|
146 | const { data, error } = useSWR('/api/user')
|
147 | // ...
|
148 | }
|
149 | ```
|
150 |
|
151 | ### `mutate`
|
152 |
|
153 | With `mutate`, you can update your local data programmatically, while
|
154 | revalidating and finally replace it.
|
155 |
|
156 | ```js
|
157 | import useSWR, { mutate } from 'swr'
|
158 |
|
159 | function Profile () {
|
160 | const { data } = useSWR('/api/user', fetcher)
|
161 |
|
162 | return <div>
|
163 | <h1>My name is {data.name}.</h1>
|
164 | <button onClick={async () => {
|
165 | const newName = data.name.toUpperCase()
|
166 | // send a request to the API to update the data
|
167 | await requestUpdateUsername(newName)
|
168 | // update the local data immediately and revalidate (refetch)
|
169 | mutate('/api/user', { ...data, name: newName })
|
170 | }}>Uppercase my name!</button>
|
171 | </div>
|
172 | }
|
173 | ```
|
174 |
|
175 | ### `trigger`
|
176 |
|
177 | You can broadcast a revalidation message to all SWR data inside any component by calling
|
178 | `trigger(key)`.
|
179 |
|
180 | ```js
|
181 | import useSWR, { trigger } from 'swr'
|
182 |
|
183 | function App () {
|
184 | return <div>
|
185 | <Profile />
|
186 | <button onClick={() => {
|
187 | // set the cookie as expired
|
188 | document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
|
189 | // tell all SWRs with this key to revalidate
|
190 | trigger('/api/user')
|
191 | }}>
|
192 | Logout
|
193 | </button>
|
194 | </div>
|
195 | }
|
196 | ```
|
197 |
|
198 | ## Examples
|
199 |
|
200 | ### Suspense Mode
|
201 |
|
202 | You can enable the `suspense` option to use `useSWR` with React Suspense.
|
203 |
|
204 | ```js
|
205 | import { Suspense } from 'react'
|
206 | import useSWR from 'swr'
|
207 |
|
208 | function Profile () {
|
209 | const { data } = useSWR('/api/user', fetcher, { suspense: true })
|
210 | return <div>hello, {data.name}</div>
|
211 | }
|
212 |
|
213 | function App () {
|
214 | return <Suspense fallback={<div>loading...</div>}>
|
215 | <Profile/>
|
216 | </Suspense>
|
217 | }
|
218 | ```
|
219 |
|
220 | ### Subscription (e.g.: socket.io)
|
221 |
|
222 | You can use SWR with socket.io (generally any subscription pattern) like this:
|
223 |
|
224 | ```js
|
225 | // fetch-data.js
|
226 |
|
227 | import { mutate } from 'swr'
|
228 |
|
229 | let latestData = null
|
230 |
|
231 | // setup ws and broadcast to all SWRs
|
232 | ...
|
233 | socket.on('data', data => {
|
234 | latestData = data
|
235 | mutate('/api/data', data, false)
|
236 | })
|
237 |
|
238 | export default () => latestData
|
239 | ```
|
240 |
|
241 | and your component:
|
242 |
|
243 | ```js
|
244 | import useSWR from 'swr'
|
245 | import fetchData from './fetch-data'
|
246 |
|
247 | function App () {
|
248 | const { data } = useSWR('/api/data', fetchData)
|
249 | // ...
|
250 | }
|
251 | ```
|
252 |
|
253 | ### Dependent Fetching
|
254 | SWR 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.
|
255 |
|
256 | ```js
|
257 | import useSWR from 'swr'
|
258 |
|
259 | function MyProjects () {
|
260 | const { data: user } = useSWR('/api/user')
|
261 | const { data: projects } = useSWR(
|
262 | () => '/api/projects?uid=' + user.id
|
263 | )
|
264 | // When passing a function, SWR will use the
|
265 | // return value as `key`. If the function throws,
|
266 | // SWR will know that some dependencies are not
|
267 | // ready. In this case it is `user`.
|
268 |
|
269 | if (!projects) return 'loading...'
|
270 | return 'You have ' + projects.length + ' projects'
|
271 | }
|
272 | ```
|
273 |
|
274 | ## Authors
|
275 | - Shu Ding ([@shuding_](https://twitter.com/shuding_)) – [ZEIT](https://zeit.co)
|
276 | - Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) – [ZEIT](https://zeit.co)
|
277 | - Joe Haddad ([@timer150](https://twitter.com/timer150)) - [ZEIT](https://zeit.co)
|
278 | - Paco Coursey ([@pacocoursey](https://twitter.com/pacocoursey)) - [ZEIT](https://zeit.co)
|
279 |
|
280 | Thanks to Ryan Chen for providing the awesome `swr` npm package name!
|
281 |
|
282 | ## License
|
283 | The MIT License.
|