5

I have a homepage with <router-link> tags to views. It is a simple master/detail relationship where the Homepage is a catalogue of products and the Product detail page/view shows information on each item.

When I first launch the website and click on an item on the Homepage view (e.g. URL: http://localhost:8080/100-sql-server-2019-licence), the Product view gets loaded and the product detail loads fine.

If I then press the back button in the browser to return to the Homepage and then click on a different Product (e.g. URL: http://localhost:8080/101-oracle-12c-licence), the URL in the browser address bar changes but I get the previous product's information. Its lightning quick and no new network calls are done which means its just showing a cached page of the previous product. If I then hit the refresh button while on that page, the network call is made and the correct product information is displayed.

I did a search online but couldn't find this problem described on the search results. Could anyone point me in the right direction of how to cause a refresh/re-render of a route when the route changes?

1 Answer 1

9

What is happening

vue-router will cache your components by default.
So when you navigate to the second product (that probably renders the same component as the first product), the component will not be instantiated again for performance reasons.

From the vue-router documentation:

For example, for a route with dynamic params /foo/:id, when we navigate between /foo/1 and /foo/2, the same Foo component instance will be reused.

The easy (but dirty) fix

The easy -but hacky and not recommended - way to solve this is to give your <router-view /> a key property, e.g.:

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

This will force vue-router to re-instantiate the view component every time the url changes.
However you will loose all performance benefits you would normally get from the caching.

Clean fix: properly handling route changes

The clean way to solve this problem is to react to the route-change in your component (mostly this boils down to moving ajax calls from mounted into a $route watcher), e.g.:

<script>
export default {
  data() {
    return {
      productDetails: null,
      loading: false
    };
  },
  watch: {
    '$route': {
      // with immediate handler gets called on first mount aswell
      immediate: true,
      // handler will be called every time the route changes.
      // reset your local component state and fetch the new data you need here.
      async handler(route) {
        this.loading = true;
        this.productDetails = null;
        try {
          // example for fetching your product data
          const res = await fetch("http://give.me.product.data/" + encodeURIComponent(route.params.id));
          this.productDetails = await res.json();
        } finally {
          this.loading = false;
        }
      }
    }
  }
};
</script>

Alternative: Navigation Guards

Alternatively you could also use vue-routers In-Component Navigation Guards to react to route changes:

<script>
export default {
  async beforeRouteUpdate (to, from, next) {
    // TODO: The route has changed.
    // The old route is in `from`, the new route in `to`.
    this.productData = await getProductDataFromSomewhere();

    // route will not change before you haven't called `next()`
    next();
  }
};
</script>
  • The downside of the navigation guards is that you can only use them directly in the component that the route renders.
    So you can't use navigation guards in components deeper within the hierarchy.
  • The upside is that the browser will not view your site before you call next(), which gives you time to load the data necessary before your route is displayed.

Some helpful ressources

Sign up to request clarification or add additional context in comments.

1 Comment

interesting, thank you. Can you explain why AppPage component DOES work properly when theyre different routes? Is it because its cached PER route in router/index.js?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.