framework icon indicating copy to clipboard operation
framework copied to clipboard

useRoute() in 'vue-router' is working but not in nuxt.

Open Nyanng opened this issue 2 years ago • 7 comments

Environment

Reproduction

https://stackblitz.com/edit/github-izskfd?file=components/Book.vue

Describe the bug

useRoute(), nuxt default provided function, has previous route information, and not updated on moving page.

But using import { useRoute } from vue-router, resolve all problems.

Is there any point I missed?

Additional context

rc.6 doesn't have problems but rc.8 has.

It just occurred as soon as updating from rc.6 to rc.8

Logs

No response

Nyanng avatar Aug 15 '22 15:08 Nyanng

/cc @danielroe

pi0 avatar Aug 15 '22 15:08 pi0

I got the same error in https://github.com/nuxt/framework/issues/6623 while using useRoute().

It seems it works again after restarting the server a couple time. I can not explain it for now. Restarting the server after the first cold start was also a workaround for #6623 if it can help.

Lyokolux avatar Aug 16 '22 08:08 Lyokolux

The key thing is that you should not destructure params from the returned route object that Nuxt (or vue-router) provides, as it is a reactive object and destructuring anything from it causes it to lose reactivity.

- const { params } = useRoute()
+ const route = useRoute()

Once fixed, note that you were effective re-implementing a route that was always one step behind the actual route in app.vue. Here is a working example, with those two issues resolved: https://stackblitz.com/edit/github-izskfd-zzrrtu

danielroe avatar Aug 16 '22 09:08 danielroe

I want to show Book Componenet with background (previous page), so I edited :route property on <NuxtPage>, still doesn't works route.params.id on Book.vue.

But I add import { useRoute } from 'vue-router' on Book.vue, it does work.

Please let me know where my mistake is...

app.vue:

...

- const route = useRoute();

const routeWithPopup = computed(() =>
+    historyState.value.background ? resolve(historyState.value.background) : undefined
);

...
...
+ <NuxtPage :route="routeWithPopup" />
...

components/Book.vue:

// When I add
// import { useRoute } from 'vue-router'
// It does work

const route = useRoute();
<!-- doesn't work with no import -->
<div>Book {{ route.params.id }}</div>

Nyanng avatar Aug 16 '22 12:08 Nyanng

I have the exact same issue. Could also throw in the fact that if I have useFetch depend on route.params it doesn't update the param I use, regardless of if I use the Options API approach or Composition API using the vue-router workaround.

Here's my code examples:

Composition API

<script setup>
  import { useRoute, useRouter } from 'vue-router';
  
  const route = useRoute();
  const { pending, data: pages, refresh } = await useLazyFetch(`/api/sites/${route.params.siteKey}/pages`);

  watch(
    () => route.params.siteKey, async siteKey => {
      refresh();
    }
  );
</script>

Options API

<script type="ts">
  import { defineComponent } from 'vue';

  export default defineComponent({
    async setup() {
      const route = useRoute();
      const { data, refresh: refreshPages } = await useFetch(`/api/sites/${route.params.siteKey}/pages`);

      return {
        pages: data.value,
        refreshPages
      }
    },
    watch: {
      '$route.params.siteKey': function(oldValue, newValue) {
        this.refreshPages();
      }
    }
  });
</script>

In both cases, the watch sees the new value and it is in fact changed. However, the refetch(), or rather useFetch does not pick up the new param and instead uses the previous one, always. So after a second route change, it uses the one from the previous route change.

@danielroe should I open a new issue regarding the useFetch portion of the issue? Or could it be considered the same issue?

themaxsandelin avatar Sep 22 '22 08:09 themaxsandelin

The issue here is that you should not import useRoute from vue-router but from #imports. We have a custom implementation of useRoute that handles some suspense related issues (https://github.com/nuxt/framework/pull/6275).

The useFetch issue you describe is already covered by https://github.com/nuxt/framework/issues/5993.

danielroe avatar Sep 22 '22 09:09 danielroe

@danielroe Regarding the vue-router import, that is only to make it possible to listen to the route params changing using the Composition API approach as mentioned above. If I don't it doesn't react to any changes, regardless of me listening to the specific param siteKey, all params or the whole route itself.

Thank you for referring me to the other issue regarding useFetch! 🙏

themaxsandelin avatar Sep 22 '22 15:09 themaxsandelin

|@danielroe hi, in my application i am changing page with NuxtLink and i am using useRoute in footer. when first load the page useRoute data works very well but after i change page fullpath doesnt change. How can i fix this can anyone help me please?

<script setup>
const route = useRoute()

const isPricing = computed(() => {
  return route.fullPath === "/blablabla"
})
</script>

"nuxt": "3.0.0-rc.11",

Ischafak avatar Oct 25 '22 08:10 Ischafak

@Ischafak my workaround (it's not very pretty) is to use state management that will refresh a variable 🤔.

In app.vue const isLink = linkStore() // I am using pinia let thisLink: string isLink.$subscribe(() => { thisLink = location.href // when the state change thisLink is updated })

BenjaminOddou avatar Oct 25 '22 13:10 BenjaminOddou

Hi there ! Tiny ping because I'm also experiencing this issue. Nuxt version 3.0.0-rc.11

Code example:

// experiences/index.js

<template>
  <div>
    <h1>Experiences</h1>
    <ul>
      <li>
        <NuxtLink to="experiences/experience1">
          <div>
            <img src="/images/exp1.png" />
          </div>
        </NuxtLink>
      </li>
      <li>
        <NuxtLink to="experiences/experience2">
          <img src="/images/exp2.png"  />
        </NuxtLink>
      </li>
    </ul>
  </div>
</template>
// experiences/[experience].js
<script setup>
import experiences from '@/data/experiences'
import { useRoute } from 'vue-router' // With this line it's working as expected

const route = useRoute()

const current = route.params.experience // This param is loaded once but never updated while the route changes
const experience = experiences[current] // So this variable always stays the same
</script>

For me too, the only way of making it work is to import manually import { useRoute } from 'vue-router'. When counting on the auto import it simply doesn't work.

PS: Note that the problem doesn't come, at least in my case, from destructuring.

Thanks!

ValJed avatar Oct 31 '22 17:10 ValJed