Security News
JSR Working Group Kicks Off with Ambitious Roadmap and Plans for Open Governance
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
The swr npm package is a React Hooks library for remote data fetching. The name 'SWR' is derived from stale-while-revalidate, a HTTP cache invalidation strategy popularized by HTTP RFC 5861. SWR is a strategy to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data.
Data Fetching
SWR provides a hook called useSWR for data fetching. You can pass a key and a fetcher function, and it will return the data, error, and other useful values for handling the UI state.
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return <div>Hello, {data.name}!</div>
}
Automatic Revalidation
SWR automatically revalidates data when a user focuses on the window or when the network is reconnected. It can also be configured to revalidate data at a fixed interval.
import useSWR from 'swr'
function Profile() {
const { data } = useSWR('/api/user', fetcher, {
refreshInterval: 3000
})
// data will be revalidated every 3 seconds
return <div>{data.name}</div>
}
Local Mutation
SWR allows you to mutate the local data immediately and revalidate it in the background. This provides an optimistic UI update experience.
import useSWR, { mutate } from 'swr'
function updateUsername(name) {
mutate('/api/user', { ...data, name }, false)
fetch('/api/user', {
method: 'POST',
body: JSON.stringify({ name })
}).then(() => {
mutate('/api/user')
})
}
React Query is another library for fetching, caching, and updating data in React applications. It provides more advanced features like query cancellation, background fetching, and even pagination helpers. React Query is often compared to SWR for its similar use cases but offers a different API and additional features.
Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. It is more complex and powerful than SWR, designed specifically for GraphQL, and provides features like caching, optimistic UI, and subscription support.
Axios is a promise-based HTTP client for the browser and Node.js. While it is not a hook-based data fetching library like SWR, it is often used for making HTTP requests in React applications. Developers would use Axios for fetching data and then manage the caching and state themselves or with additional libraries.
SWR is a React Hooks library for remote data fetching.
The name “SWR” is derived from stale-while-revalidate
, a cache invalidation strategy popularized by HTTP RFC 5861.
SWR first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.
It features:
...and a lot more.
With SWR, components will get a stream of data updates constantly and automatically. Thus, the UI will be always fast and reactive.
import useSWR from 'swr'
function Profile () {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
In this example, the React Hook useSWR
accepts a key
and a fetcher
function.
key
is a unique identifier of the request, normally the URL of the API. And the fetcher
accepts
key
as its parameter and returns the data asynchronously.
useSWR
also returns 2 values: data
and error
. When the request (fetcher) is not yet finished,
data
will be undefined
. And when we get a response, it sets data
and error
based on the result
of fetcher
and rerenders the component.
Note that fetcher
can be any asynchronous function, so you can use your favourite data-fetching
library to handle that part.
Check out swr.now.sh for more demos of SWR, and Examples for the best practices.
Inside your React project directory, run the following:
yarn add swr
Or with npm:
npm install swr
const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)
key
: a unique key string for the request (or a function / array / null) (advanced usage)fetcher
: (optional) a Promise returning function to fetch your data (details)options
: (optional) an object of options for this SWR hookdata
: data for the given key resolved by fetcher
(or undefined if not loaded)error
: error thrown by fetcher
(or undefined)isValidating
: if there's a request or revalidation loadingmutate
: function to mutate the cached datasuspense = false
: enable React Suspense mode (details)fetcher = undefined
: the default fetcher functioninitialData
: initial data to be returned (note: This is per-hook)revalidateOnFocus = true
: auto revalidate when window gets focusedrevalidateOnReconnect = true
: automatically revalidate when the browser regains a network connection (via navigator.onLine
)refreshInterval = 0
: polling interval (disabled by default)refreshWhenHidden = false
: polling when the window is invisible (if refreshInterval
is enabled)refreshWhenOffline = false
: polling when the browser is offline (determined by navigator.onLine
)shouldRetryOnError = true
: retry when fetcher has an error (details)dedupingInterval = 2000
: dedupe requests with the same key in this time spanfocusThrottleInterval = 5000
: only revalidate once during a time spanloadingTimeout = 3000
: timeout to trigger the onLoadingSlow eventerrorRetryInterval = 5000
: error retry interval (details)errorRetryCount
: max error retry count (details)onLoadingSlow
: callback function when a request takes too long to load (see loadingTimeout
)onSuccess
: callback function when a request finishes successfullyonError
: callback function when a request returns an erroronErrorRetry
: handler for error retrycompare
: comparison function used to detect when returned data has changed, to avoid spurious rerenders. By default, fast-deep-equal is used.When under a slow network (2G, <= 70Kbps), errorRetryInterval
will be 10s, and
loadingTimeout
will be 5s by default.
You can also use global configuration to provide default options.
The context SWRConfig
can provide global configurations (options
) for all SWR hooks.
In this example, all SWRs will use the same fetcher provided to load JSON data, and refresh every 3 seconds by default:
import useSWR, { SWRConfig } from 'swr'
function Dashboard () {
const { data: events } = useSWR('/api/events')
const { data: projects } = useSWR('/api/projects')
const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // don't refresh
// ...
}
function App () {
return (
<SWRConfig
value={{
refreshInterval: 3000,
fetcher: (...args) => fetch(...args).then(res => res.json())
}}
>
<Dashboard />
</SWRConfig>
)
}
fetcher
is a function that accepts the key
of SWR, and returns a value or a Promise.
You can use any library to handle data fetching, for example:
import fetch from 'unfetch'
const fetcher = url => fetch(url).then(r => r.json())
function App () {
const { data } = useSWR('/api/data', fetcher)
// ...
}
Or using GraphQL:
import { request } from 'graphql-request'
const API = 'https://api.graph.cool/simple/v1/movies'
const fetcher = query => request(API, query)
function App () {
const { data, error } = useSWR(
`{
Movie(title: "Inception") {
releaseDate
actors {
name
}
}
}`,
fetcher
)
// ...
}
If you want to pass variables to a GraphQL query, check out Multiple Arguments.
Note that fetcher
can be omitted from the parameters if it's provided globally.
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.
// conditionally fetch
const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
// ...or return a falsy value
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
// ... or throw an error when user.id is not defined
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
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.
function MyProjects () {
const { data: user } = useSWR('/api/user')
const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
// When passing a function, SWR will use the
// return value as `key`. If the function throws,
// SWR will know that some dependencies are not
// ready. In this case it is `user`.
if (!projects) return 'loading...'
return 'You have ' + projects.length + ' projects'
}
In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher
function. For example:
useSWR('/api/user', url => fetchWithToken(url, token))
This is incorrect. Because the identifier (also the index of the cache) of the data is '/api/data'
,
so even if token
changes, SWR will still have the same key and return the wrong data.
Instead, you can use an array as the key
parameter, which contains multiple arguments of fetcher
:
const { data: user } = useSWR(['/api/user', token], fetchWithToken)
// ...and pass it as an argument to another query
const { data: orders } = useSWR(user ? ['/api/orders', user] : null, fetchWithUser)
The key of the request is now the combination of both values. SWR shallowly compares
the arguments on every render, and triggers revalidation if any of them has changed.
Keep in mind that you should not recreate objects when rendering, as they will be treated as different objects on every render:
// Don’t do this! Deps will be changed on every render.
useSWR(['/api/user', { id }], query)
// Instead, you should only pass “stable” values.
useSWR(['/api/user', id], (url, id) => query(url, { id }))
Dan Abramov explains dependencies very well in this blog post.
You can broadcast a revalidation message globally to all SWRs with the same key by calling
mutate(key)
.
This example shows how to automatically refetch the login info (e.g.: inside <Profile/>
)
when the user clicks the “Logout” button.
import useSWR, { mutate } from 'swr'
function App () {
return (
<div>
<Profile />
<button onClick={() => {
// set the cookie as expired
document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
// tell all SWRs with this key to revalidate
mutate('/api/user')
}}>
Logout
</button>
</div>
)
}
In many cases, applying local mutations to data is a good way to make changes feel faster — no need to wait for the remote source of data.
With mutate
, you can update your local data programmatically, while
revalidating and finally replace it with the latest data.
import useSWR, { mutate } from 'swr'
function Profile () {
const { data } = useSWR('/api/user', fetcher)
return (
<div>
<h1>My name is {data.name}.</h1>
<button onClick={async () => {
const newName = data.name.toUpperCase()
// send a request to the API to update the data
await requestUpdateUsername(newName)
// update the local data immediately and revalidate (refetch)
mutate('/api/user', { ...data, name: newName })
}}>Uppercase my name!</button>
</div>
)
}
Clicking the button in the example above will send a POST request to modify the remote data, locally update the client data and try to fetch the latest one (revalidate).
But many POST APIs will just return the updated data directly, so we don’t need to revalidate again.
Here’s an example showing the “local mutate - request - update” usage:
mutate('/api/user', newUser, false) // use `false` to mutate without revalidation
mutate('/api/user', updateUser(newUser)) // `updateUser` is a Promise of the request,
// which returns the updated document
In many cases, you are receiving a single value back from your API and want to update a list of them.
With mutate
, you can pass an async function which will receive the current cached value, if any, and let you return an updated document.
mutate('/api/users', async users => {
const user = await fetcher('/api/users/1')
return [user, ...users.slice(1)]
})
Most probably, you need to data mutate used to update the cache when you passed a promise or async function.
The function will returns the updated document, or throw an error, everytime you call it.
try {
const user = await mutate('/api/user', updateUser(newUser))
} catch (error) {
// Handle an error while updating the user here
}
With the initialData
option, you pass an initial value to the hook. It works perfectly with many SSR solutions
such as getServerSideProps
in Next.js:
export async function getServerSideProps() {
const data = await fetcher('/api/data')
return { props: { data } }
}
function App (props) {
const initialData = props.data
const { data } = useSWR('/api/data', fetcher, { initialData })
return <div>{data}</div>
}
It is still a server-side rendered site, but it’s also fully powered by SWR in the client side. Which means the data can be dynamic and update itself over time and user interactions.
You can enable the suspense
option to use SWR with React Suspense:
import { Suspense } from 'react'
import useSWR from 'swr'
function Profile () {
const { data } = useSWR('/api/user', fetcher, { suspense: true })
return <div>hello, {data.name}</div>
}
function App () {
return (
<Suspense fallback={<div>loading...</div>}>
<Profile/>
</Suspense>
)
}
In Suspense mode, data
is always the fetch response (so you don't need to check if it's undefined
).
But if an error occurred, you need to use an error boundary to catch it.
Note that Suspense is not supported in SSR mode.
By default, SWR uses the exponential backoff algorithm to handle error retries. You can read more from the source code.
It's also possible to override the behavior:
useSWR(key, fetcher, {
onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
if (retryCount >= 10) return
if (error.status === 404) return
// retry after 5 seconds
setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
}
})
There’re many ways to prefetch the data for SWR. For top level requests, rel="preload"
is highly recommended:
<link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">
This will prefetch the data before the JavaScript starts downloading. And your incoming fetch requests will reuse the result (including SWR, of course).
Another choice is to prefetch the data conditionally. You can have a function to refetch and set the cache:
function prefetch () {
mutate('/api/data', fetch('/api/data').then(res => res.json()))
// the second parameter is a Promise
// SWR will use the result when it resolves
}
And use it when you need to preload the resources (for example when hovering a link).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.
Thanks to Ryan Chen for providing the awesome swr
npm package name!
The MIT License.
FAQs
React Hooks library for remote data fetching
The npm package swr receives a total of 1,842,139 weekly downloads. As such, swr popularity was classified as popular.
We found that swr demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 8 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
Security News
Research
An advanced npm supply chain attack is leveraging Ethereum smart contracts for decentralized, persistent malware control, evading traditional defenses.
Security News
Research
Attackers are impersonating Sindre Sorhus on npm with a fake 'chalk-node' package containing a malicious backdoor to compromise developers' projects.