Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to hook in afterEach after the transition #1968

Closed
DaxChen opened this issue Jan 8, 2018 · 7 comments
Closed

Ability to hook in afterEach after the transition #1968

DaxChen opened this issue Jan 8, 2018 · 7 comments
Labels
fixed on 4.x This issue has been already fixed on the v4 but exists in v3 group[transition wrapped views] Issues regarding things not being in-sync on hooks because of a transition improvement

Comments

@DaxChen
Copy link

DaxChen commented Jan 8, 2018

What problem does this feature solve?

When implementing analytics with vue-router, we often rely on the router.afterEach hook. For example:

router.afterEach((to, from) => {
  ga('set', 'page', to.fullPath)
  ga('send', 'pageview')
})

However, when there is a page transition (and obviously the page transition will use mode="out-in"), the new component will wait for the old component to fade out first, but the afterEach hook was already fired.

In the about example, say the user was originally on the home page with page title "home" and clicks on the /about link:

  1. The url changes immediately, and afterEach hook fires. ga called to track pageview, but got the old title "home" by calling document.title.
  2. The home page fades out, and finally destroyed.
  3. The about page gets mounted (and fades in), page title and other metadata get modified (in my case I'm using vue-meta

In this comment, @posva recommend using Vue.nextTick. I tried adding multiple nextTicks but doesn't work...

What does the proposed API look like?

Is it possible to perhaps dynamically register a mounted hook (without overriding original one) to the to component in afterEach?
For example:

router.afterEach((to, from) => {
  // some kind of way to get the page component
  to.$el.mounted = () => {
    ga('set', 'page', to.fullPath)
    ga('send', 'pageview')
  }
})

Or maybe add a new hook that will wait for page transition to finish, and the new component mounted?

router.afterEachMounted((to, from) => {
  ga(...)
})

Thank you all so much!!!

Dax

@posva
Copy link
Member

posva commented Jan 26, 2018

There are indeed some improvements to have in the navigation cycle to allow users branch anywhere. Specifically when dealing with transitions

@DaxChen
Copy link
Author

DaxChen commented May 10, 2018

I wonder if there is any temporarily workarounds? Without hard-coding something like setTimout(trackingCode, transitionDuration) in router.afterEach

@studstill
Copy link

Leverage Vue.nextTick to wait for DOM updates before firing analytics events

router.afterEach((to, from) => {
  Vue.nextTick(() => {
    ga(...)
  })
})

@DaxChen
Copy link
Author

DaxChen commented Sep 16, 2018

@studstill
Thank you! In a lot of case nextTick is really useful.

However, in the case where router-view is wrapped in transition mode="out-in", router.afterEach is actually called right when the old page starts to fade out.

Even with nextTick, the ga(...) call is called one tick after the old page starts to fade out, still resulting in getting the old document.title...

@posva posva added the group[transition wrapped views] Issues regarding things not being in-sync on hooks because of a transition label Mar 26, 2019
@posva posva changed the title afterEach with mounted hook Ability to hook in afterEach after the transition Mar 26, 2019
@ericcirone
Copy link

Any updates on this? I'm having the same issues.

@posva posva added the fixed on 4.x This issue has been already fixed on the v4 but exists in v3 label Mar 6, 2020
@posva
Copy link
Member

posva commented May 26, 2020

I'm closing this in favor of #2079

@posva posva closed this as completed May 26, 2020
@Rigo-m
Copy link

Rigo-m commented Feb 27, 2024

@posva sorry for hijacking this issue, hope you don't mind.

For anyone looking into this issue with nuxt 3 - vue-router stack , and trying to send events to GA after the DOM title has been updated (for example) vue-router is not where you should look into!
Instead of navigation guards, which handles navigation we need to hook into unhead to know when meta params has changed.
Heres the relevant code:

import { getActiveHead } from "unhead";

export const useHeadChange = (cb: (() => Promise<void>) | (() => void)) => {
  const lastDomRenderState = useState("unhead:dom-render-state", () => ({}));
  const head = getActiveHead();
  head?.hooks.addHooks({
    "dom:rendered": async (ctx) => {
      const stringifiedCtx = JSON.stringify(ctx);
      if (lastDomRenderState.value !== stringifiedCtx) {
        lastDomRenderState.value = stringifiedCtx;
        await cb();
      }
    },
  });
};

Use this composable in App.vue like so:

<script setup lang="ts">
useHeadChange(() => {
    console.log(document.title)
})
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed on 4.x This issue has been already fixed on the v4 but exists in v3 group[transition wrapped views] Issues regarding things not being in-sync on hooks because of a transition improvement
Projects
None yet
Development

No branches or pull requests

5 participants