Subscribe on changes!

watchEffect within `effectScope()` stops working after navigating away from then back to component

avatar
Jan 30th 2023

Reproduction

Playground SFC

Steps to reproduce the bug

  1. Navigate to the TestView component in the browser
  2. Click the button, testData count property is incremented
  3. Navigate away from it (staying in the SPA)
  4. Navigate back to TestView

Expected behavior

The button should cause testData.count to be incremented, even after re-mounting the component.

Actual behavior

After navigating back to the component clicking the button updates the refresher, but not testData

testStore.js?t=1675088280233:17 Refresher: 0.05272026601141877
testStore.js?t=1675088280233:11 Watch effect running 0.05272026601141877
testStore.js?t=1675088280233:17 Refresher: 0.937791768731258
testStore.js?t=1675088280233:11 Watch effect running 0.937791768731258
# Navigate away
logger.js:197 [Router] BeforeEach /passes
logger.js:197 [Router] AfterEach: /passes
# Then back
logger.js:197 [Router] BeforeEach /test
logger.js:197 [Router] AfterEach: /test
testStore.js?t=1675088280233:17 Refresher: 0.558079237843816
testStore.js?t=1675088280233:17 Refresher: 0.31739197899941574
avatar
Jan 30th 2023

Trasfered from pinia and updated the reproduction. This is similar to https://github.com/vuejs/core/issues/7319 but not exactly the same. Use a regular watch() as a workaround.

avatar
Jan 30th 2023

I cannot use a regular watch, as I mentioned the sample code above is an inlined version of VueUse:computedAsync.

Here is the original store:

import { defineStore } from "pinia"
import { epClient } from "@/common-services/epClient"
import { recomputedAsync } from "@/common-services/vue-recomputed-async"
import urlcat from "urlcat"

export const useRegisterStore = defineStore("RegisterStore", () => {

  function logError(e) {
    console.log("ComputedAsync error: " + JSON.stringify(e))
  }

  const { data: passes, refresh: refreshPasses } =
    recomputedAsync(async () => {
      return await epClient.get("/register/passes")
    }, [], { onError: logError })

const savePass = async (pass) => {
    try {
      await epClient...
    } finally {
      refreshPasses()
    }
  }
avatar
Jan 30th 2023

The linked issue put me on the right track, calling useXxxStore from main.js before the Vue app is mounted is a valid workaround, watchEffect gets called with currentInstance = null and the effect works normally.

avatar
Jan 31st 2023

@posva

Trasfered from pinia and updated the reproduction. This is similar to #7319 but not exactly the same. Use a regular watch() as a workaround.

I think the root cause is exactly the same and @LinusBorg 's PR will fix this. see

avatar
Jan 31st 2023

hmm, maybe something after cd7c887b755810aedf83f3d458cb956d5b147f6f broke this then? because it fails on the latest commit on the main branch

avatar
Feb 2nd 2023

@posva duplicate of https://github.com/vuejs/core/issues/7319 it works on the latest version. see

avatar
Feb 2nd 2023

Now I see that the import maps were version-fixed and had the wrong version of Vue 🥲