GithubHelp home page GithubHelp logo

kong / swrv Goto Github PK

View Code? Open in Web Editor NEW
2.1K 35.0 71.0 2.06 MB

Stale-while-revalidate data fetching for Vue

Home Page: https://docs-swrv.netlify.app

License: Apache License 2.0

JavaScript 1.46% TypeScript 97.84% Shell 0.70%
vue swr

swrv's Introduction

swrv

npm 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:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Interval polling
  • SSR support (removed as of version 0.10.0 - read more)
  • Vue 3 Support
  • Revalidation on focus
  • Request deduplication
  • TypeScript ready
  • Minimal API
  • Stale-if-error
  • Customizable cache implementation
  • Error Retry

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

The version of swrv you install depends on the Vue dependency in your project.

Vue 3

# Install the latest version
yarn add swrv

Vue 2.7

This version removes the dependency of the external @vue/composition-api plugin and adds vue to the peerDependencies, requiring a version that matches the following pattern: >= 2.7.0 < 3

# Install the 0.10.x version for Vue 2.7
yarn add swrv@v2-latest

Vue 2.6 and below

If you're installing for Vue 2.6.x and below, you may want to check out a previous version of the README to view how to initialize swrv utilizing the external @vue/composition-api plugin.

# Install the 0.9.x version for Vue < 2.7
yarn add swrv@legacy

Getting Started

<template>
  <div>
    <div v-if="error">failed to load</div>
    <div v-if="!data">loading...</div>
    <div v-else>hello {{ data.name }}</div>
  </div>
</template>

<script>
import useSWRV from 'swrv'

export default {
  name: 'Profile',

  setup() {
    const { data, error } = useSWRV('/api/user', fetcher)

    return {
      data,
      error,
    }
  },
}
</script>

In this example, the Vue Hook 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. When omitted, swrv falls back to the browser Fetch API.

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 reactive reference / watcher function / null) (advanced usage)
fetcher a Promise returning function to fetch your data. If null, swrv will fetch from cache only and not revalidate. If omitted (i.e. undefined) then the fetch api will be used.
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

See Config Defaults

  • 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.
  • shouldRetryOnError = true - retry when fetcher has an error
  • errorRetryInterval = 5000 - error retry interval
  • errorRetryCount: 5 - max error retry count
  • 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.

<template>
  <p v-if="!projects">loading...</p>
  <p v-else>You have {{ projects.length }} projects</p>
</template>

<script>
import { ref } from 'vue'
import useSWRV from 'swrv'

export default {
  name: 'Profile',

  setup() {
    const { data: user } = useSWRV('/api/user', fetch)
    const { data: projects } = useSWRV(() => user.value && '/api/projects?uid=' + user.value.id, fetch)
    // if the return value of the cache key function is falsy, the fetcher
    // will not trigger, but since `user` is inside the cache key function,
    // it is being watched so when it is available, then the projects will
    // be fetched.

    return {
      user,
      projects
    }
  },
}
</script>

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.

<template>
  <div v-if="error">failed to load</div>
  <div v-if="data === undefined && !error">loading...</div>
  <p v-if="data">
    hello {{ data.name }} of {{ data.birthplace }}. This content will continue
    to appear even if future requests to {{ endpoint }} fail!
  </p>
</template>

<script>
import { ref } from 'vue'
import useSWRV from 'swrv'

export default {
  name: 'Profile',

  setup() {
    const endpoint = ref('/api/user/Geralt')
    const { data, error } = useSWRV(endpoint.value, fetch)

    return {
      endpoint,
      data,
      error,
    }
  },
}
</script>

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'

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:

<template>
  <div>
    <div v-if="[STATES.ERROR, STATES.STALE_IF_ERROR].includes(state)">
      {{ error }}
    </div>
    <div v-if="[STATES.PENDING].includes(state)">Loading...</div>
    <div v-if="[STATES.VALIDATING].includes(state)">
      <!-- serve stale content without "loading" -->
    </div>
    <div
      v-if="
        [STATES.SUCCESS, STATES.VALIDATING, STATES.STALE_IF_ERROR].includes(
          state
        )
      "
    >
      {{ data }}
    </div>
  </div>
</template>

<script>
import { computed } from 'vue'
import useSwrvState from '@/composables/useSwrvState'
import useSWRV from 'swrv'

export default {
  name: 'Repo',
  setup(props, { root }) {
    const page = computed(() => root.$route.params.id)
    const { data, error, isValidating } = useSWRV(
      () => `/api/${root.$route.params.id}`,
      fetcher
    )
    const { state, STATES } = useSwrvState(data, error, isValidating)

    return {
      state,
      STATES,
      data,
      error,
      page,
      isValidating,
    }
  },
}
</script>

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

Vue 3 example:

<script>
import { defineComponent, ref, computed, watch } from 'vue'
import { useStore } from 'vuex'
import useSWRV from 'swrv'
import { getAllTasks } from './api'

export default defineComponent({
  setup() {
    const store = useStore()

    const tasks = computed({
      get: () => store.getters.allTasks,
      set: (tasks) => {
        store.dispatch('setTaskList', tasks)
      },
    })

    const addTasks = (newTasks) => store.dispatch('addTasks', { tasks: newTasks })

    const { data } = useSWRV('tasks', getAllTasks)

    // Using a watcher, you can update the store with any changes coming from swrv
    watch(data, newTasks => {
      store.dispatch('addTasks', { source: 'Todoist', tasks: newTasks })
    })

    return {
      tasks
    }
  },
})
</script>

Cache

By default, a custom cache implementation is used to store fetcher response data cache, in-flight promise cache, and ref cache. Response data cache can be customized via the config.cache property. Built in cache adapters:

localStorage

A common usage case to have a better offline experience is to read from localStorage. Checkout the PWA example for more inspiration.

import useSWRV from 'swrv'
import LocalStorageCache from 'swrv/dist/cache/adapters/localStorage'

function useTodos () {
  const { data, error } = useSWRV('/todos', undefined, {
    cache: new LocalStorageCache('swrv'),
    shouldRetryOnError: false
  })

  return {
    data,
    error
  }
}

Serve from cache only

To only retrieve a swrv cache response without revalidating, you can set the fetcher function to null 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 composables with a null fetcher will have data available. This isn't very intuitive, so will be looking for ways to improve this api in the future.

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

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

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) 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 watcher, 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 mutate 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

🤔

Adam DeHaven

💻 📖 🚧

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

swrv's People

Contributors

adamdehaven avatar axelhzf avatar bikingbadger avatar charshin avatar darrenjennings avatar dependabot[bot] avatar jefrailey avatar kamilic avatar kiaking avatar luminisward avatar mascii avatar mptap avatar neolsn avatar reslear avatar simowe avatar slauzinho avatar solufa avatar souljorje avatar tochoromero avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swrv's Issues

Settings to work on Vercel?

Hi there,

It seems to be quite slow in fetching data via Vercel. I believe this is due to it not really setting state-while-revalidate. Is there special settings that must be used with Nuxt for this to work?

Cannot read property '$isServer' of null

Should useSWRV work in an on click handler? I'm getting the following error

[Vue warn]: Error in v-on handler: "TypeError: Cannot read property '$isServer' of null"

found in

---> <Home> at src/views/Home.vue
       <App> at src/App.vue
         <Root>
vue.runtime.esm.js?2b0e:1888 TypeError: Cannot read property '$isServer' of null
    at useSWRV (use-swrv.js?7713:86)
    at onClick (Home.vue?76f2:16)
    at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
    at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
    at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6917)

Here is a minimal reproduction:

<template>
	<div>
		<button @click="onClick">Click me</button>
	</div>
</template>

<script>
import useSWRV from 'swrv';

const fetcher = async (key) => {
	return key;
};

export default {
	setup() {
		const onClick = () => {
			const { data } = useSWRV('test', fetcher);
			console.log(data)
		};

		return {
			onClick,
		};
	},
};
</script>

Typescript issue with @vue/composition-api > beta.6

After upgrading composition api, I'm getting the following issue:

<template>
<div v-if="data">
   {{data.foo}} <!-- Property 'foo' does not exist on type 'Ref<{ foo: string; } | undefined> -->
</template>

I traced it down to the definition of IResponse

interface IResponse {
    data?: Ref......
}

removing the ? makes it work again.

it most likely has to do with vuejs/core#1682 which was implemented in beta.7

I couldn't see that any of the examples given fit this one, but perhaps this is another breaking example

vue 3 support

composition-api is a peerDep, but vue 3.x is in beta, so we should begin to test vue 3 as a peer dep as well

Optimistic local mutations

Hello! First thanks for the great library, it's really great to have a SWR alternative with Vue 😍

I was wanting to do optimistic updates (like documented at SWR here https://swr.vercel.app/docs/mutation#mutation-and-post-request)

I'm not sure if it's possible to do the same: do a mutation of the cache without triggering a revalidation, and later do a revalidation. I've tried but didn't have success.

If it is, I think it would be really interesting to have it documented! Thanks again!

How to "await" for fetch data from SWRV?

I am trying to access the data object that is fetched from SWRV, but sometimes it is not there yet, so it is coming up undefined. Is there a way to get this data from SWRV using await/async?

Thanks.

Module parse failed: Unexpected token (183:54)

I've been trying to find a solution to my compilation issue. I am using the newest version of Vue CLI with Vue @2.6.11. I believe it's due to Vue CLI's method of using webpack but I can't figure out what the unexpected token is. Any thoughts?

Failed to compile.

./node_modules/swrv/esm/use-swrv.js 183:54
Module parse failed: Unexpected token (183:54)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|         }
|         const fetcher = data || fn;
>         if (!fetcher || !isDocumentVisible() || (opts?.forceRevalidate !== undefined && !opts?.forceRevalidate)) {
|             stateRef.isValidating = false;
|             return;

Get last known state of data if there is no `fn`

In the case, we want to share data between components.

For example, there is an app config needs to be got from network when app is starting.

// in component App
const { data: appConfig } = useSWRV('/app/config', configFetcher);
....
// in component B
const { data: appConfig } = useSWRV('/app/config');

Serve from Cache only after the first successful response

Hey, i really like this libary.
I tried to use this hook to only serve from cache after the first successful response without an extra cache checking if statement. I tried this but i doesnt seem to work.

const { data } = useSWRV(key, fetcher, { dedupingInterval: Number.MAX_SAFE_INTEGER })

In React Query i can do

const { data } = useQuery(key, fetcher, { staleTime: Infinity })

I am missing something or is this not possible right now?

We have some backend enums resources which only need to be loaded once.

dedupingInterval not working on vue 3?

I have setup dedupingInterval but it's not working, it requests it every time I change to that page, even if inside the safe internval. It should not make a request.

Not working in Nuxt v2.14.5 ?

I have spent a while trying to get this to work with the latest version of Nuxt, but it does not seem possible. I keep getting
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file for Fetcher. The examples for SSR in this repo are using 2.11. Is there something in more recent versions that break this?

Edit: This may be an issue on my end I am not sure. I am getting odd results. Can you confirm with works with latest version of Nuxt?

Edit 2: It seems like it may have been from using the latest version of @vue/composition-api.

refactor(examples-basic): explain or don't destructure props in setup function

FTR: destructuring the props in the setup function is not advised since it removes reactivity, see https://v3.vuejs.org/guide/composition-api-setup.html#props

To mitigate future issues when users copy-paste this example, it might be good to either explain that reactivity isn't needed, or follow along with the composition-api-setup guide and not destructure props in setup arguments:

setup ({ org }) {

`data` and `error` cannot be `undefined` by themselves

Problem

interface SomeDataType {
  foo: string;
}

async function fetcher(): Promise<SomeDataType> {
  return { foo: 'test' }
}

const { data, error } = useSWRV('some-key', fetcher);

// const data: Ref<SomeDataType | undefined> | undefined
// const error: Ref<any> | undefined

Why can the values data and error themselves be undefined? This is not really what is happening. They are always some kind of Ref with values, they cannot be undefined by themselves. The code snippets below confirm this.

// https://github.com/Kong/swrv/blob/03b853191cb00d48f51f8edbdbbe3216e8847bf5/src/use-swrv.ts#L203

stateRef = reactive({
  data: undefined,
  error: undefined,
  isValidating: true,
  key: null
}) as StateRef<Data, Error>

// -- snip --

// https://github.com/Kong/swrv/blob/03b853191cb00d48f51f8edbdbbe3216e8847bf5/src/use-swrv.ts#L389

const res: IResponse = {
  ...toRefs(stateRef),
  mutate: (data, opts: revalidateOptions) => revalidate(data, {
    ...opts,
    forceRevalidate: true
  })
}

return res

This code shows that data and error will always be Ref<Data> and Ref<Error>, not Ref<Data> | undefined and Ref<Error> | undefined.

I think the IResponse interface should be fixed:

// now
export interface IResponse<Data = any, Error = any> {
  data?: Ref<Data | undefined>;
  error?: Ref<Error | undefined>;
  isValidating: Ref<boolean>;
  mutate: () => Promise<void>;
}

// should be
export interface IResponse<Data = any, Error = any> {
  data: Ref<Data | undefined>;
  // ^ remove '?'
  error: Ref<Error | undefined>;
  // ^ remove '?'
  isValidating: Ref<boolean>;
  mutate: () => Promise<void>;
}

Anyway, thanks for the swrv, it's great!

Cannot read property '$isServer' of null

I'm trying out swrv in the following environment.

  • vite.
  • swrv@beta
  • axios@latest

Use axios as a swrv fetcher. (Like the nuxt example.)
However, this did not work. When I tried to run it, I got the following error in the console.

runtime-dom.esm-bundler-9cc07ca3.js:1258 TypeError: Cannot read property '$isServer' of null
    at useSWRV (swrv.js:137)
    at useRequest (fetch.ts?t=1595862507218:12)
    at Proxy.getPokeData (App.vue:22)
    at _createVNode.onClick._cache.<computed>. _cache.<computed> (App.vue:40)
    at callWithErrorHandling (runtime-dom.esm-bundler-9cc07ca3.js:1199)
    at callWithAsyncErrorHandling (runtime-dom.esm-bundler-9cc07ca3.js:1208)
    at HTMLButtonElement.invoker (runtime-dom.esm-bundler-9cc07ca3.js:7481)

I ran getCurrentInstance and checked, the vm.$isServer does not exist.

Am I doing something wrong? Or will swrv + axios not work in a vite environment?

My repository is here. Thanks for the great effort.
https://github.com/ushironoko/swrv-example

Mutate doesn't recheck dependent key

Hi again,

I've found that when doing mutate() of a useSWRV query, the key is not validated again.

Example:

useUser.js

export default function useUser() {
  const checkIsValid = () => {
    console.log('ACCESSSED CHECK IS VALID');
    return false;
  };
  return useSWRV(() => checkIsValid() && 'user', fetchUser);
}

In a component:

<template>
  <button @click="checkAgain">CHECK</button>
</template>
<script>
import useUser from '../hooks/useUser.js';

export default {
  setup(){
    const { mutate, data } = useUser();

    const checkAgain = () => {mutate()};

    return {checkAgain}
   }
}
</script>

The function checkIsValid is only executed once (when the component loads). When I do mutate() the checkIsValid is not executed, as so, its always false. If the first time is true, every time is executed. So it's not validating it again.

In my case I wanted to check the token stored at the localstorage, but found out that it's not checking it.

Thanks.

Function-based Keys bail Nuxt Hydration

When using functions as keys for useSWRV, nuxt fails to rehydrate with the cache. I believe this is because the function is not called (see line 134)

useSWRV uses keyRef and assumes that keyRef is a ref, despite the function check on line 123.

In testing, I've been able to get this to work by re-checking if keyRef is a function and if so calling it, otherwise accessing value like such:

const instanceState = nodeState[isRef(keyRef) ? keyRef.value : keyRef()]

However, I'm not sure if this would have any unintended side effects.

race conditions on changing key swrv cache key

The REF_CACHE allows for mutate to update all cached swrv instances, but if you change the cache key (which triggers a revalidation), the refs on the instance e.g. data, error, etc. are still updating inside the component scope based on the resolution of the previous revalidations. This is because revalidations will update the refs to the resolution of an old revalidation even if the cache key has changed. Once a cache key changes, the revalidations should be "cancelled" or rather prevented from updating the refs on the instance since the key has changed. This isn't usually very noticeable because revalidations typically resolve before the next one, but if you're firing many consecutively it is more noticeable as the data starts to update frequently when it should only update if the key of the revalidation resolution is equal to the current key. Should be as simple as checking if the cache key of the revalidation that fired is equal to the current cache key.

Hello, Friends.

Is there no ongoing maintenance for this library (Vue3 version)? It feels good, I like it!

data response type should be inferred from fetcher fn type

Fetchers should type the data response:

interface IRes {
  id: number
}

function fetcher(url): Promise<IRes> {
  return new Promise((resolve) => resolve({id:1})
}

const { data } = useSWRV('cache-key', fetcher);
//      ^^^^ should be typed as IRes

Workaround (not great):

// tell swrv what to type
const { data } = useSWRV<IRes>('cache-key', fetcher);

Allow array as key, multiple arguments to fetcher

In the parameter documentation, the readme mentions that it is possible to pass an array as a cache key to useSWRV, presumably to allow passing multiple arguments to the fetch function as SWR does.

Currently, this does not work and it brakes the caching completely.

Is there a plan to support this feature, or is there another way to pass multiple arguments to the fetcher function?

The behavior is unexpected when TTL value was set to 0

https://github.com/Kong/swrv/blob/master/src/use-swrv.ts#L45

Sometimes we prefetch data when starting app.

mutate('/api/appConfig', fetcher);

and then use that data until use close window.

const { data } = useSWRV('/api/appConfig');

Because of the ttl, that data can be only kept 5 minutes.
That forced us need to do something like below.

mutate('/api/appConfig', fetcher, undefined, 1000 * 60 * 60 * 24 * 365);
const { data } = useSWRV('/api/appConfig', undefined, { ttl: 1000 * 60 * 60 * 24 * 365 });

I've looked the source codes. I know if the ttl is 0 means keeping the data and the refs forever.
So, could you please let the default ttl be 0?

SSR mode shares cache between requests

I think that a shared cache between different requests can be dangerous. The cache can contain user information and you could send information from user1 to user 2.

I think that the problem is that the default cache is declared as a variable at the module level https://github.com/Kong/swrv/blob/master/src/use-swrv.ts#L15

A solution could be to pass my own cache instance and be sure that it is unique by request

// default.vue
setup() {
   provide('requestCache', new SWRVCache())
}

// page.vue
setup() {
   const requestCache = provide('requestCache')
   useSWRV('key', fetcher, { cache: requestCache })
}

But what about the other caches? REF_CACHE and PROMISES_CACHE?

Another possible solution could be to bound the default caches (data, ref and promises) to the current vue instance. This way we can be sure that every request has its own instance.

When first load is not on active tab, data is not fetched

When doing a load of a page while not in focus (we switch tab or have browser in background,...) requests are not made. I think we would like to have a first load of content and later revalidate on focus, but not have everything empty until the user focuses the page. Or if it's intended I believe it should be configurable. :)

Thanks so much!

Request key not reactive in setup?

I have a very simple component:

export default defineComponent({
  name: "User",
  props: {
    "user_id": String
  },
  setup(props) {
    const {data, error} = useSWRV(`/api/user/${props.user_id}`, fetcher);

    return {
      data,
      error,
    };
  }
});

And in my Vue router, I am passing the user_id from the url fragment (/user/:user_id) via props: true.

According to my readings of the docs, once the user_id prop is updated (on navigation or manual URL change), so should the data. However, this doesn't happen.

(I can verify the prop is in fact being updated by setting up a watch that just prints it out when it changes; and changing the string interpolation syntax to a simple string concat makes no difference.)

I am using Vue v3.0.0, swrv v1.0.0-beta.4.

edit: It's definitely possible that I'm misunderstanding the Composition API which I'm learning at the moment, but I assume this would be a common use case, so I would definitely enjoy if this were mentioned in docs for people like me :)

typing fixes, code review

This library was written in typescript, but I think there's a few things making it not "Typescript Ready", like we want. Soliciting a code review / accepting PR's.

Is realtime (Mercure, WebSocket...) supported?

Hi, first of all thanks for this awesome library.

Is it possible to automatically trigger a refresh of the view when the data is mutated? For instance I use Mercure (an alternative to Websocket) to push new versions of the resources to the client. I would like the view to update when a new event is received, it works with SWR but it seems that it doesn't work (yet?) with SWRv. Here is what I tried:

import { mutate } from 'swrv'

// ...
eventSource.onmessage = (e: MessageEvent) => {
      mutate(absoluteURL, Promise.resolve(JSON.parse(e.data)))
}

Mutate is called successfully, but unlike with SWR the currently displayed data doesn't update automatically. Am I missing something or is this not supported yet?

Best regards,

Infinite Pagination

How would you do infinite pagination? In other words, when a new result comes in, you add it to the cache instead of clobbering it.

handle errors gracefully when dependently fetching

If I use an async fetcher, I get the following error in my console. It does actually work once the first call resolves. Is there more I should be doing, or some way to get rid of the errors?

vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in getter for watcher "function () {
      return "/api/users/".concat(user.value.id, "/profile");
    }": "TypeError: Cannot read property 'id' of undefined"

I've setup a simple test project with effectively the same code as shown here https://guuu.io/2020/data-fetching-vue-composition-api/#swrv

<template>
	<div class="home">
		<div>{{ profile.firstName }} {{ profile.lastName }}</div>
		<div>{{ user.username }}</div>
	</div>
</template>

<script>
import useSWRV from 'swrv';

const fetcher = async (key) => {
	if (key === '/api/users/john') {
		return { id: 1, username: 'john' };
	} else if (key === '/api/users/1/profile') {
		return { firstName: 'John', lastName: 'Doe' };
	}
};

export default {
	name: 'UserProfile',

	props: {
		username: {
			type: String,
			required: true,
		},
	},

	setup(props) {
		const { data: user } = useSWRV(`/api/users/${props.username}`, fetcher);
		const { data: profile } = useSWRV(() => `/api/users/${user.value.id}/profile`, fetcher);

		return {
			user,
			profile,
		};
	},
};
</script>

Here is the route for completeness sake

	{
		path: '/profile/:username',
		component: () => import('../views/Profile.vue'),
		props: (route) => ({ username: route.params.username }),
	},

SSR does not rehydrate correctly when there are multiple swrv usages

When there are multiple usages, the SSR does not work correctly.

<template>
  <div class="container">
    <div v-if="data1">{{ data1 }}</div>
    <div v-if="data2">{{ data2 }}</div>
  </div>
</template>
<script>
import useSWRV from 'swrv';
export default {
  setup() {
    const { data: data1 } = useSWRV('post1', () => fetchPostById(1));
    const { data: data2 } = useSWRV('post2', () => fetchPostById(2));
    return { data1, data2 }
  }
}

The server returns the correct HTML, but when the client is loaded, both usages contains the same data.

Here is a repository with the problem:

https://github.com/axelhzf/swrv-ssr-bug

roadmap and/or production readiness?

I was actually looking to move a Vue 2 project to React since i loved working with SWR in my day job, quick google brought me here. Few questions around the roadmap and production readiness.

  1. what is the plan for Vue 3 support? or is the plan to keep this Vue 2 + @vue/composition-api or a bit longer? I saw there was a "beta" branch but that seems weird since this is still not a 1.0 release
  2. would you add this to a production app in it's current state?

Thanks for all the hard work, looking forward to pulling this into my future projects.

cache.ts API divergent from localStoreCache example in pwa and README

LocalStoreCache class in pwa example has very different interface than the memory version in cache.ts (different params, methods missing). Also, the README has an even more out of date example of that class. Ideally LocalStoreCache is an alternative option that is maintained and available in the library itself.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.