Repository: Kong/swrv
Pull request #73 (2020-08-11 03:13:22)

refactor(document-visible): modify isDocumentVisible timing
Consider this scenario.
1. A user triggered a long time task to get a data, which might be longer than 15 seconds, in page A. `useSWRV('dynamicKey', fetcher)`
2. Re-route to page B after the task done. The page B need to be constructed with data from that task. 

Issue:
If the user switch to another Chrome tab when the task was running, then the page B won't be setup properly.
Because the page B won't get data when calling `useSWRV('dynamicKey')`.

Expected:
Should get data last known state when UI setup in document invisible mode.

BTW, in SWR, you can get last known state, but won't trigger the fetcher.
https://github.com/vercel/swr/blob/e76d30973bf623149ac4a61c81b0d3e4c8d79d93/src/use-swr.ts#L238-L253


darrenjennings: @NeoLSN what is the bug exactly?
NeoLSN: > @NeoLSN what is the bug exactly?

Oh, I forgot to update description.

Patch:
diff --git a/src/use-swrv.ts b/src/use-swrv.ts
index 3a93df4..4b143a1 100644
--- a/src/use-swrv.ts
+++ b/src/use-swrv.ts
@@ -177,7 +177,8 @@ export default function useSWRV<Data = any, Error = any> (key: IKey, fn?: fetche
    */
   const revalidate = async (data?: fetcherFn<Data>) => {
     const keyVal = keyRef.value
-    if (!isDocumentVisible() || !keyVal) { return }
+    if (!keyVal) { return }
+
     const cacheItem = config.cache.get(keyVal)
     let newData = cacheItem && cacheItem.data
 
@@ -188,7 +189,7 @@ export default function useSWRV<Data = any, Error = any> (key: IKey, fn?: fetche
     }
 
     const fetcher = data || fn
-    if (!fetcher) {
+    if (!fetcher || !isDocumentVisible()) {
       stateRef.isValidating = false
       return
     }
@@ -229,8 +230,7 @@ export default function useSWRV<Data = any, Error = any> (key: IKey, fn?: fetche
       // if this is the case, but continue to revalidate since promises can't
       // be cancelled and new hook instances might rely on promise/data cache or
       // from pre-fetch
-      if (!stateRef.error && isDocumentVisible() && isOnline()) {
-        // only revalidate when the page is visible
+      if (!stateRef.error && isOnline()) {
         // if API request errored, we stop polling in this round
         // and let the error retry function handle it
         await revalidate()


Test patch:
diff --git a/tests/use-swrv.spec.tsx b/tests/use-swrv.spec.tsx
index 8550e78..7003a8f 100644
--- a/tests/use-swrv.spec.tsx
+++ b/tests/use-swrv.spec.tsx
@@ -956,6 +956,77 @@ describe('useSWRV - window events', () => {
     done()
   })
 
+  it('should get last known state when document is not visible', async done => {
+    let count = 0
+    mutate('dynamic-5-1', count)
+    toggleVisibility('hidden')
+
+    const vm = new Vue({
+      template: `<div>count: {{ data }}</div>`,
+      setup () {
+        return useSWRV('dynamic-5-1', () => ++count, {
+          refreshInterval: 200
+        })
+      }
+    }).$mount()
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 0')
+    expect(count).toBe(0)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 0')
+    expect(count).toBe(0)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 0')
+    expect(count).toBe(0)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 0')
+    expect(count).toBe(0)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 0')
+    expect(count).toBe(0)
+
+    toggleVisibility('visible')
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 1')
+    expect(count).toBe(1)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 1')
+    expect(count).toBe(1)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 2')
+    expect(count).toBe(2)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 2')
+    expect(count).toBe(2)
+
+    timeout(200)
+    await tick(vm, 1)
+    expect(vm.$el.textContent).toBe('count: 3')
+    expect(count).toBe(3)
+
+    vm.$destroy()
+
+    done()
+  })
+
   it('should not rerender when offline', async done => {
     let count = 0