23

I have one auth component that I am using both in the login and the signup route.

const routes = [{
  path     : '/',
  name: 'home',
  component: Home
}, {
  path     : '/signin',
  name: 'signin',
  component: Auth
},
  {
    path     : '/signup',
    name: 'signup',
    component: Auth
  }];

If for example, I'm on the login page The problem is if I type something in the text inputs and go to the signup the text is still there, how I force the component to reinitialize?

1
  • if possible, provide a jsfiddle, so better help can be provided. Commented Nov 30, 2016 at 9:17

4 Answers 4

63

The better way to do this is actually to bind the routes path to the router-view's key, i.e.

<router-view :key="$route.path"></router-view>

Doing so will force Vue to create a new instance of the component.

EDIT

Updated to provide a meta key you could add which would allow you to disable the reuse of components only for the routes you require. this would need refining if you wanted to work with it on routes that are more than 1 level deep - but it gives you the idea.

const Foo = {
  name: 'foo',
	data () {
    	return {
        	inputText: '',
        }
    },
	template: `
    	<div class="box">
        	<h1>{{ $route.path }}</h1>
            <input type="text" v-model="inputText">
        </div>
    `,
}

const Baz = {
  name: 'baz',
	data () {
    	return {
        	inputText: '',
        }
    },
	template: `
    	<div class="box">
        	<h1>{{ $route.path }}</h1>
            <input type="text" v-model="inputText">
        </div>
    `,
}

const routes = [
  { path: '/foo', component: Foo, meta: { reuse: false }, },
  { path: '/bar', component: Foo, meta: { reuse: false }, },
  { path: '/baz', component: Baz },
  { path: '/bop', component: Baz }
]

const router = new VueRouter({
  routes
})

const app = new Vue({
  router,
  data: {
    key: null,
  },
}).$mount('#app')

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.reuse === false)) {
    app.key = to.path
  } else {
    app.key = null
  }
  next()
})
#content {
    position: relative;   
  height: 200px;
}

.box {
    position: absolute;
    top: 0;
    left: 0;
    width: 200px;
    height: 200px;
    background: rgba(0,0,0, 0.2);
    text-align: center;
    transform: translate3d(0, 0, 0);
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/[email protected]"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
    <router-link to="/baz">Go to Baz</router-link>
    <router-link to="/bop">Go to Bop</router-link>
  </p>
  <div id="content">
      <router-view :key="key"></router-view>
  </div>
  <pre>{{ key }}</pre>
</div>

This then allows you to combine your router-view with Vues transition system so it becomes pretty awesome!

3
  • 1
    The problem with this approach that this will be globally to all components.
    – user7122183
    Commented Nov 30, 2016 at 14:54
  • if you use a dynamic key then you can control how "global" it is, will update above
    – GuyC
    Commented Nov 30, 2016 at 15:17
  • 2
    updated above to allow enabling of this feature only on desired routes, via the routes meta param
    – GuyC
    Commented Nov 30, 2016 at 15:44
9

You can use the key attribute to indicate vue to rerender some elements instead of reusing them.

e.g. you have an <input/> in your Auth component which you want to rerender under different routes, add a key data prop to Auth, use <input :key="key"/> in the template. In your case here,

data() {
    key: this.$route.path
}

may be a good choice.

3
  • lol - I literally was pasting my answer as you posted! Upvoted you - but I did also nail the fiddle! :)
    – GuyC
    Commented Nov 30, 2016 at 14:21
  • @GuyC Well reading this the word 缘分 comes to my mind. Also I always quite respect those who write long answers with detailed, real-world examples with perfection...
    – JJPandari
    Commented Nov 30, 2016 at 14:32
  • thanks dude - impressive how we both answered 5 hours later with the same answer!
    – GuyC
    Commented Nov 30, 2016 at 14:35
2

vuejs caches rendered component. you don't provide Auth component code, but i think the following helps you.

<template>
     <input type="text" ID="username" v-model="usernameinput">
     <!-- other text boxes and inputs -->
</template>
export default {
    name: 'Auth',
    //component code .....
    data: function() {
        return {
            usernameinput: '',
            //and other stuff
        }
    },
    watch: {
        // call method if the route changes
        '$route': 'reInitialize'
    },
    methods: {
        reInitialize: function() {
            this.usernameinput = '';
            //and so on
        }
    },
    //remainig component code
}

also there is another posibilty, may be you are using dynamic components and keep-alive is true.

5
  • No I am not using keep alive just regular component
    – user7122183
    Commented Nov 30, 2016 at 9:17
  • so, the watch and methods part should be the way. Commented Nov 30, 2016 at 9:19
  • Are you sure this is the only way?
    – user7122183
    Commented Nov 30, 2016 at 9:19
  • No! :-) I'm not sure, but this is what i use Commented Nov 30, 2016 at 9:20
  • Ok I will wait for more answers before marking yours. thanks.
    – user7122183
    Commented Nov 30, 2016 at 9:21
-1

You should watch route params and when it changes, re-execute to fetch data. Example

created() {
// watch the params of the route to fetch the data again
this.$watch(
  () => this.$route.params,
  () => {
    this.fetchData()
  },
  // fetch the data when the view is created and the data is
  // already being observed
  { immediate: true }
)

},

More info at https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-after-navigation

1
  • It does not answer the question. The code snippet you shared is about fetching data while the component is loading. It's not about the case when the component wasn't unmounted on route change (the question)
    – Dvdgld
    Commented Feb 16, 2022 at 20:36