Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - Regaron/swr: React Hooks library for remote data fetching · GitHub
Skip to content

Repository files navigation

SWR

Introduction

swr.now.sh

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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

...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.


Quick Start

importuseSWRfrom'swr'functionProfile(){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.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const{ data, error, isValidating, revalidate }=useSWR(key,fetcher,options)

Parameters

  • 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 hook

Return Values

  • data: 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 loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

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.


Examples

Global Configuration

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:

importuseSWR,{SWRConfig}from'swr'functionDashboard(){const{data: events}=useSWR('/api/events')const{data: projects}=useSWR('/api/projects')const{data: user}=useSWR('/api/user',{refreshInterval: 0})// don't refresh// ...}functionApp(){return(<SWRConfigvalue={{refreshInterval: 3000,fetcher: (...args)=>fetch(...args).then(res=>res.json())}}><Dashboard/></SWRConfig>)}

Data Fetching

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:

importfetchfrom'unfetch'constfetcher=url=>fetch(url).then(r=>r.json())functionApp(){const{ data }=useSWR('/api/data',fetcher)// ...}

Or using GraphQL:

import{request}from'graphql-request'constAPI='https://api.graph.cool/simple/v1/movies'constfetcher=query=>request(API,query)functionApp(){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.

Conditional Fetching

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 fetchconst{ data }=useSWR(shouldFetch ? '/api/data' : null,fetcher)// ...or return a falsy valueconst{ data }=useSWR(()=>shouldFetch ? '/api/data' : null,fetcher)// ... or throw an error when user.id is not definedconst{ data }=useSWR(()=>'/api/data?uid='+user.id,fetcher)

Dependent Fetching

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.

functionMyProjects(){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'}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/data',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:

useSWR(['/api/data',token],fetchWithToken)

This solves the problem. 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)// Make sure objects are stableconstparams=useMemo(()=>({ id }),[id])useSWR(['/api/user',params],query)

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

importuseSWR,{trigger}from'swr'functionApp(){return(<div><Profile/><buttononClick={()=>{// set the cookie as expireddocument.cookie='token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'// tell all SWRs with this key to revalidatetrigger('/api/user')}}>
Logout
</button></div>)}

Mutation and Post Request

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.

importuseSWR,{mutate}from'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher)return(<div><h1>My name is {data.name}.</h1><buttononClick={async()=>{constnewName=data.name.toUpperCase()// send a request to the API to update the dataawaitrequestUpdateUsername(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 revalidationmutate('/api/user',updateUser(newUser))// `updateUser` is a Promise of the request,// which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps=async()=>{constdata=awaitfetcher('/api/data')return{ data }}functionApp(props){constinitialData=props.dataconst{ 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.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import{Suspense}from'react'importuseSWRfrom'swr'functionProfile(){const{ data }=useSWR('/api/user',fetcher,{suspense: true})return<div>hello, {data.name}</div>}functionApp(){return(<Suspensefallback={<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.

Error Retries

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)returnif(error.status===404)return// retry after 5 secondssetTimeout(()=>revalidate({retryCount: retryCount+1}),5000)}})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<linkrel="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:

functionprefetch(){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 hoveringalink).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

About

React Hooks library for remote data fetching

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages