vuejs / composition-api

Composition API plugin for Vue 2
https://composition-api.vuejs.org/
MIT License
4.19k stars 342 forks source link

Vue Router in Composition API? #197

Closed rogeralsing closed 4 years ago

rogeralsing commented 4 years ago

I'm coming up short on information how to access the $router when using composition API.

All leads point to ctx.root.$router, everyone I've asked says this should be the way to get hold of the router. But, it is undefined. Other plugins such as Vue Resource show up as ctx.root.$http. but router does not.

My setup looks as such:

import Vue from "vue";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import "roboto-fontface/css/roboto/roboto-fontface.css";
import "@mdi/font/css/materialdesignicons.css";
import "material-design-icons-iconfont/dist/material-design-icons.css";

Vue.config.productionTip = false;
import vueResource from "vue-resource";
import VirtualCollection from 'vue-virtual-collection'
import VueCompositionApi from "@vue/composition-api"
import VueRouter from "vue-router";
Vue.use(VueCompositionApi);
Vue.use(VueRouter);
Vue.use(vueResource);
Vue.use(VirtualCollection);

Vue.http.options.emulateJSON = true;

new Vue({
  vuetify,
  render: h => h(App)
}).$mount("#app");

inside any setup, the above issue persists.

setup(props,ctx) {
  console.log(ctx.root.$router); //undefined
  ...
}

Am I missing some step? is there some other way to access the router so that I can push new urls to navigate via code?

LinusBorg commented 4 years ago

Well, I don't see you actually creatingf a router instance anywhere, all you do is install the plugin, but not use it, so ...

If your example code is incomplete, complete it. if that's actually all you have, please read the usage instructions for Vue Router again about how to set it up.

rogeralsing commented 4 years ago

Setup is as follows:

  const router = new VueRouter({
    mode: "history",
    routes: [
      {
        path: "/",
        component: Content,
        props: {user: state.user}
      },
      {
        path: "/login",
        component: Login,
        props: {user: state.user}
      },
      {
        path: "/register",
        component: Register,
        props: {user: state.user}
      },
      {
        path: "/content",
        component: Content,
        props: {user: state.user}
      },
      {
        path: "/profile",
        component: Profile,
        props: {user: state.user}
      }
    ]
  });

  router.beforeEach((to, from, next) => {
    ...auth code...

    next();
  });

  export default {
    router,   //<- the router
    name: "App",
    props: {
      source: String
    },
    components: {},
    data: () => ({
      drawer: null,
      state
    }),
  };
LinusBorg commented 4 years ago

I see.

Well, root points ot the root instance, which is the one created with new Vue().

You on the other hand, add the router not in root, but in the first child component, App (which is technically valid, but unusual). So in root, there's no router.

The usual way to add the router is to import it into main.js and add it to new Vue()'s options: then it will work via root.$router as expected.

rogeralsing commented 4 years ago

Many thanks, this solved it.

gokhantaskan commented 4 years ago
setup(props, vm) {
    ...
    vm.root.$options.router.push({ name: "Overview" });
    ...
}

It works for me but the problem is that I don't have the router directly under the root.

Version: "@vue/composition-api": "^0.4.0"

F-loat commented 4 years ago
// src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  ...
})

export default router
import router from '@/router'

export default {
  setup() {
    const { currentRoute } = router

    if (currentRoute.query.redirect) {
      // ...
      return
    }

    router.push({ name: "Overview" })
  }
}
eithed commented 4 years ago

@F-loat this solution doesn't seem to work - currentRoute returns / when on any route