6

I'm trying to access useRoute from within a composable function. Starting with vue 3.3.2 & vue-route 4.2.0, I set up a test using npm init vue@latest with the router enabled. No problem accessing useRoute via the composition API within the 'script setup' tag:

App.vue

<script setup>
import { RouterLink, RouterView } from 'vue-router'

import { useRoute } from 'vue-router'
const route = useRoute()

import { computed } from 'vue'
const path = computed(() => {
  console.log(`step 1`)
  if (!route) {
    console.log(`step 2`)
    return
  }
  if (!route.path) {
    console.log(`step 3`)
    return
  }
  console.log(`step 4`)
  return route.path
})
</script>

<template>
  <p>path = {{ path }}</p>
  <header>
    <nav>
      <RouterLink to="/">Home</RouterLink>
      <RouterLink to="/about">About</RouterLink>
    </nav>
  </header>

  <RouterView />
</template>

In the above code, the computed function is re-calculated each times the route changes, reaching step 1 then step 4 (success).

But when I move this code to a composable it breaks:

App.vue

<script setup>
import { RouterLink, RouterView } from 'vue-router'
import path from '@/composables/useRouteTest'
</script>

composables/useRouteTest.js

import { useRoute } from 'vue-router'
const route = useRoute()

import { computed } from 'vue'
const path = computed(() => {
  console.log(`step 1`)
  if (!route) {
    console.log(`step 2`)
    return
  }
  if (!route.path) {
    console.log(`step 3`)
    return
  }
  console.log(`step 4`)
  return route.path
})

export default {
  path
}

Within the composable, the computed function never progresses beyond step 2, and is only called once, even when I navigate to different routes.

Does useRoute not work within composables?

I've spend many hours trying the following alternatives: different Vue versions; using watch instead of computed; 'useRouter' rather than 'useRoute'; using watch with async invocation (https://router.vuejs.org/guide/advanced/composition-api.html). Always the same result.

1 Answer 1

6

useRoute is only available for use inside script setup. What you can do in the composable is wrap its usage in a function then import and call the function from your component. This is the recommended way to make most composables so they can share the context of the component they're called from.

composables/useRouteTest.js

import { useRoute } from 'vue-router'
import { computed } from 'vue'

export function useRouteTest() {
  const route = useRoute()

  const path = computed(() => {
    console.log(`step 1`)
    if (!route) {
      console.log(`step 2`)
      return
    }
    if (!route.path) {
      console.log(`step 3`)
      return
    }
    return route.path
  })

  return {
    path
  }
}

App.vue

<script setup>
import { useRouteTest } from '@/composables/useRouteTest'

const { path } = useRouteTest()
</script>
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks yoduh, works perfectly and your explanation clears up my confusion. I somehow missed this point in the documentation.
@Jaqen if this answers your question, please consider accepting this as the solution.
Since useRoute() is a composable and not a utility, I don't understand why it should not be used in another composable / outside the setup function. Where did you find that information @yoduh? There is one catch though – useRoute() is not reactive. That caused problems for me. You can however access useRouter().currentRoute which returns the same information but as a ref.
Vue's restrictions on composables explains why they should only be used inside setup functions. Also, the object returned by useRoute() is reactive, from the docs: "The route object is a reactive object"... To explain why the useRoute object is not reactive in your case would require exploring the circumstances of that unique case (feel free to make a new question about it).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.