Repository: Kong/swrv (ts)

Issue:
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!


Pull request description:
fix(*) fetches data on first render
even when document is not visible

Fixes #128 

Patch:
diff --git a/src/use-swrv.ts b/src/use-swrv.ts
index ee56cf0..c467481 100644
--- a/src/use-swrv.ts
+++ b/src/use-swrv.ts
@@ -218,6 +218,7 @@ function useSWRV<Data = any, Error = any> (...args): IResponse<Data, Error> {
    * Revalidate the cache, mutate data
    */
   const revalidate = async (data?: fetcherFn<Data>, opts?: revalidateOptions) => {
+    const isFirstFetch = stateRef.data === undefined
     const keyVal = keyRef.value
     if (!keyVal) { return }
 
@@ -231,7 +232,11 @@ function useSWRV<Data = any, Error = any> (...args): IResponse<Data, Error> {
     }
 
     const fetcher = data || fn
-    if (!fetcher || !config.isDocumentVisible() || (opts?.forceRevalidate !== undefined && !opts?.forceRevalidate)) {
+    if (
+      !fetcher ||
+      (!config.isDocumentVisible() && !isFirstFetch) ||
+      (opts?.forceRevalidate !== undefined && !opts?.forceRevalidate)
+    ) {
       stateRef.isValidating = false
       return
     }


Test patch:
diff --git a/tests/use-swrv.spec.tsx b/tests/use-swrv.spec.tsx
index 73f59fd..7502c3f 100644
--- a/tests/use-swrv.spec.tsx
+++ b/tests/use-swrv.spec.tsx
@@ -1199,17 +1199,22 @@ describe('useSWRV - error', () => {
 })
 
 describe('useSWRV - window events', () => {
-  const toggleVisibility = state => Object.defineProperty(document, 'visibilityState', {
+  const toggleVisibility = (state: VisibilityState) => Object.defineProperty(document, 'visibilityState', {
     configurable: true,
-    get: function () { return state }
+    get: function (): VisibilityState { return state }
   })
 
-  const toggleOnline = state => Object.defineProperty(navigator, 'onLine', {
+  const toggleOnline = (state: boolean) => Object.defineProperty(navigator, 'onLine', {
     configurable: true,
-    get: function () { return state }
+    get: function (): boolean { return state }
   })
 
-  it('should not rerender when document is not visible', async done => {
+  afterEach(() => {
+    toggleOnline(true)
+    toggleVisibility('visible')
+  })
+
+  it('should not rerender when document is not visible', async () => {
     let count = 0
 
     const vm = new Vue({
@@ -1240,14 +1245,9 @@ describe('useSWRV - window events', () => {
     expect(vm.$el.textContent).toBe('count: 1')
 
     vm.$destroy()
-
-    // put it back to visible for other tests
-    toggleVisibility('visible')
-
-    done()
   })
 
-  it('should get last known state when document is not visible', async done => {
+  it('should get last known state when document is not visible', async () => {
     let count = 0
     mutate('dynamic-5-1', count)
     toggleVisibility('hidden')
@@ -1262,32 +1262,22 @@ describe('useSWRV - window events', () => {
       }
     }).$mount()
 
+    // first fetch always renders #128
     timeout(200)
     await tick(1)
-    expect(vm.$el.textContent).toBe('count: 0')
-    expect(count).toBe(0)
-
-    timeout(200)
-    await tick(1)
-    expect(vm.$el.textContent).toBe('count: 0')
-    expect(count).toBe(0)
-
-    timeout(200)
-    await tick(1)
-    expect(vm.$el.textContent).toBe('count: 0')
-    expect(count).toBe(0)
+    expect(vm.$el.textContent).toBe('count: 1')
+    expect(count).toBe(1)
 
     timeout(200)
     await tick(1)
-    expect(vm.$el.textContent).toBe('count: 0')
-    expect(count).toBe(0)
+    expect(vm.$el.textContent).toBe('count: 1')
+    expect(count).toBe(1)
 
+    // subsequent fetches while document is hidden do not rerender
     timeout(200)
     await tick(1)
-    expect(vm.$el.textContent).toBe('count: 0')
-    expect(count).toBe(0)
-
-    toggleVisibility('visible')
+    expect(vm.$el.textContent).toBe('count: 1')
+    expect(count).toBe(1)
 
     timeout(200)
     await tick(1)
@@ -1299,6 +1289,8 @@ describe('useSWRV - window events', () => {
     expect(vm.$el.textContent).toBe('count: 1')
     expect(count).toBe(1)
 
+    toggleVisibility('visible')
+
     timeout(200)
     await tick(1)
     expect(vm.$el.textContent).toBe('count: 2')
@@ -1314,12 +1306,20 @@ describe('useSWRV - window events', () => {
     expect(vm.$el.textContent).toBe('count: 3')
     expect(count).toBe(3)
 
-    vm.$destroy()
+    timeout(200)
+    await tick(1)
+    expect(vm.$el.textContent).toBe('count: 3')
+    expect(count).toBe(3)
 
-    done()
+    timeout(200)
+    await tick(1)
+    expect(vm.$el.textContent).toBe('count: 4')
+    expect(count).toBe(4)
+
+    vm.$destroy()
   })
 
-  it('should not rerender when offline', async done => {
+  it('should not rerender when offline', async () => {
     let count = 0
 
     const vm = new Vue({
@@ -1349,7 +1349,28 @@ describe('useSWRV - window events', () => {
     await tick(1)
     // should not rerender cuz offline
     expect(vm.$el.textContent).toBe('count: 1')
+  })
 
-    done()
+  // https://github.com/Kong/swrv/issues/128
+  it('fetches data on first render even when document is not visible', async () => {
+    toggleVisibility('hidden')
+
+    const vm = new Vue({
+      template: `<div>{{ data }}</div>`,
+      setup  () {
+        const { data, error } = useSWRV(
+          'fetches-data-even-when-document-is-not-visible',
+          () => new Promise(res => setTimeout(() => res('first'), 100))
+        )
+        return { data, error }
+      }
+    }).$mount()
+
+    expect(vm.$el.textContent).toBe('')
+
+    timeout(100)
+    await tick()
+
+    expect(vm.$el.textContent).toBe('first')
   })
 })