swrv

by Kong

Kong /swrv

Stale-while-revalidate data fetching for Vue

598 Stars 19 Forks Last release: about 1 month ago (v0.7.3) Apache License 2.0 98 Commits 14 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

swrv

build

swrv
(pronounced "swerve") is a library using the @vue/composition-api for remote data fetching. It is largely a port of swr.

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.

Features:

  • [x] Transport and protocol agnostic data fetching
  • [x] Fast page navigation
  • [x] Revalidation on focus
  • [x] Interval polling
  • [x] Request deduplication
  • [x] TypeScript ready
  • [x] Minimal API
  • [x] stale-if-error
  • [x] Customizable cache implementation
  • [x] SSR support
  • [x] Vue 3 Support

With

swrv
, components will get a stream of data updates constantly and automatically. Thus, the UI will be always fast and reactive.

Table of Contents

Installation

$ yarn add swrv

If you want to try out Vue 3 support (beta), install the beta release and check out the Vite example.

$ yarn add [email protected]

Getting Started

In this example,

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

useSWRV
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. This is because
data
and
error
are Vue Refs, and their values will be set by the fetcher response.

Note that fetcher can be any asynchronous function, so you can use your favorite data-fetching library to handle that part.

Api

const { data, error, isValidating, mutate } = useSWRV(key, fetcher, options)

Parameters

| Param | Required | Description | | --------- | -------- | ----------------------------------------------------------------------------------- | |

key
| yes | a unique key string for the request (or a watcher function / null) (advanced usage) | |
fetcher
| | a Promise returning function to fetch your data (details) | |
options
| | an object of configuration options |

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

Config options

  • refreshInterval = 0
    - polling interval in milliseconds. 0 means this is disabled.
  • dedupingInterval = 2000
    - dedupe requests with the same key in this time span
  • ttl = 0
    - time to live of response data in cache. 0 mean it stays around forever.
  • revalidateOnFocus = true
    - auto revalidate when window gets focused
  • revalidateDebounce = 0
    - debounce in milliseconds for revalidation. Useful for when a component is serving from the cache immediately, but then un-mounts soon thereafter (e.g. a user clicking "next" in pagination quickly) to avoid unnecessary fetches.
  • cache
    - caching instance to store response data in. See src/lib/cache, and Cache below.

Prefetching

Prefetching can be useful for when you anticipate user actions, like hovering over a link. SWRV exposes the

mutate
function so that results can be stored in the SWRV cache at a predetermined time.
import { mutate } from 'swrv'

function prefetch() { mutate( '/api/data', fetch('/api/data').then((res) => res.json()) ) // the second parameter is a Promise // SWRV will use the result when it resolves }

Dependent Fetching

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

Stale-if-error

One of the benefits of a stale content caching strategy is that the cache can be served when requests fail.

swrv
uses a stale-if-error strategy and will maintain
data
in the cache even if a
useSWRV
fetch returns an
error
.

State Management

useSwrvState

Sometimes you might want to know the exact state where swrv is during stale-while-revalidate lifecyle. This is helpful when representing the UI as a function of state. Here is one way to detect state using a user-land composable

useSwrvState
function:
import { ref, watchEffect } from '@vue/composition-api'

const STATES = { VALIDATING: 'VALIDATING', PENDING: 'PENDING', SUCCESS: 'SUCCESS', ERROR: 'ERROR', STALE_IF_ERROR: 'STALE_IF_ERROR', }

export default function(data, error, isValidating) { const state = ref('idle') watchEffect(() => { if (data.value && isValidating.value) { state.value = STATES.VALIDATING return } if (data.value && error.value) { state.value = STATES.STALE_IF_ERROR return } if (data.value === undefined && !error.value) { state.value = STATES.PENDING return } if (data.value && !error.value) { state.value = STATES.SUCCESS return } if (data.value === undefined && error) { state.value = STATES.ERROR return } })

return { state, STATES, } }

And then in your template you can use it like so:

Vuex

Most of the features of swrv handle the complex logic / ceremony that you'd have to implement yourself inside a vuex store. All swrv instances use the same global cache, so if you are using swrv alongside vuex, you can use global watchers on resolved swrv returned refs. It is encouraged to wrap useSWRV in a custom composable function so that you can do application level side effects if desired (e.g. dispatch a vuex action when data changes to log events or perform some logic).

Cache

By default, a custom cache implementation is used to store both fetcher response data cache, and in-flight promise cache. Response data cache can be customized via the

config.cache
property.
import { SWRVCache } from 'swrv'

class NoCache extends SWRVCache { get(k: string, ttl: number): any {} set(k: string, v: any) {} delete(k: string) {} }

const { data, error } = useSWRV(key, fetch, { cache: new NoCache() })

localStorage

A common usage case to have a better offline experience is to read from

localStorage
. Checkout the PWA example for more inspiration.
class LocalStorageCache extends SWRVCache {
  STORAGE_KEY = 'swrv'

private encode (storage) { return btoa(JSON.stringify(storage)) } private decode (storage) { return JSON.parse(atob(storage)) }

get (k, ttl) { const item = localStorage.getItem(this.STORAGE_KEY) if (item) { return JSON.parse(atob(item))[k] } }

set (k, v) { let payload = {} const storage = localStorage.getItem(this.STORAGE_KEY) if (storage) { payload = this.decode(storage) payload[k] = { data: v, ttl: Date.now() } } else { payload = { [k]: { data: v, ttl: Date.now() } } }

localStorage.setItem(this.STORAGE_KEY, this.encode(payload))

} }

const myCache = new LocalStorageCache()

export default { setup () { return useSWRV(key, fetch, { cache: myCache }) } }

Serve from cache only

To only retrieve a swrv cache response without revalidating, you can omit the fetcher function from the useSWRV call. This can be useful when there is some higher level swrv composable that is always sending data to other instances, so you can assume that fetcher-less composables will have data available.

// Component A 
const { data } = useSWRV('/api/config', fetcher)

// Component B, only retrieve from cache const { data } = useSWRV('/api/config')

Error Handling

Since

error
is returned as a Vue Ref, you can use watchers to handle any onError callback functionality. Check out the test.
export default {
  setup() {
    const { data, error } = useSWRV(key, fetch)

function handleError(error) {
  console.error(error && error.message)
}

watch(error, handleError)

return {
  data,
  error,
}

}, }

FAQ

How is swrv different from the swr react library?

Vue and Reactivity

The

swrv
library is meant to be used with the @vue/composition-api (and eventually Vue 3) library so it utilizes Vue's reactivity system to track dependencies and returns vue
Ref
's as it's return values. This allows you to watch
data
or build your own computed props. For example, the key function is implemented as Vue
watch
er, so any changes to the dependencies in this function will trigger a revalidation in
swrv
.

Features

Features were built as needed for

swrv
, and while the initial development of
swrv
was mostly a port of swr, the feature sets are not 1-1, and are subject to diverge as they already have.

Why does swrv make so many requests?

The idea behind stale-while-revalidate is that you always get fresh data eventually. You can disable some of the eager fetching such as

config.revalidateOnFocus
, but it is preferred to serve a fast response from cache while also revalidating so users are always getting the most up to date data.

How can I refetch swrv data to update it?

Swrv fetcher functions can be triggered on-demand by using the

revalidate
return value. This is useful when there is some event that needs to trigger a revalidation such a PATCH request that updates the initial GET request response data.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Darren Jennings

💻 📖

Sébastien Chopin

💻 🤔

Fernando Machuca

🎨

ZEIT

🤔

Jason Yang/楊朝傑

🐛 💻

Axel Hernández Ferrera

🐛 💻 💡

This project follows the all-contributors specification. Contributions of any kind welcome!

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.