最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - The recommended way to load route data before entering the route? - Stack Overflow

programmeradmin4浏览0评论

Before rendering a page for a given route, I'd like to synchronously fetch the necessary data first. Ideally, I'd like to have the data fetching within the page ponent, but I'm not opposed to doing it in the router files. I've read and tried various ways of doing it, but part of the challenge es from the fact that there are also multiple ways of building ponents and the usage of certain features vary.

In my case, I'm building single file ponents using the Composition API and <script setup> syntax. The Vue Router documentation link talks about "fetching before navigation" in which I could reach for beforeRouteEnter or beforeRouteUpdate, but this is shown using the Options API. They do have the page for the Composition API mentioning I could use onBeforeRouteUpdate, but that uses the setup() function. I figured I'd try it out anyway with <script setup>:

<script setup>
import { onBeforeRouteUpdate } from 'vue-router'

onBeforeRouteUpdate(() => {
  console.log('onBeforeRouteUpdate')
})
</script>

However, this does not execute. The closest method I've tried that works is fetching the data in the router, using the beforeEnter guard, and setting the data onto the meta property, which can then get accessed on the route instance in the ponent:

beforeEnter: (to, from, next) => {
  fetch('')
    .then(res => res.json())
    .then(res => {
    to.meta.pokemon = res;

    next();
  });
}

But with this, which is noted in the documentation, beforeEnter only triggers when entering the route. Params changes will not retrigger this, meaning that I'd have to set up a watcher on the route in the ponent anyway. I might as well just have had all this logic in the ponent itself.

I just can't seem to find a good way to do this, but I might have overlooked something. If anyone has some pointers or advice, I'd appreciate it. Thanks in advance.

Before rendering a page for a given route, I'd like to synchronously fetch the necessary data first. Ideally, I'd like to have the data fetching within the page ponent, but I'm not opposed to doing it in the router files. I've read and tried various ways of doing it, but part of the challenge es from the fact that there are also multiple ways of building ponents and the usage of certain features vary.

In my case, I'm building single file ponents using the Composition API and <script setup> syntax. The Vue Router documentation link talks about "fetching before navigation" in which I could reach for beforeRouteEnter or beforeRouteUpdate, but this is shown using the Options API. They do have the page for the Composition API mentioning I could use onBeforeRouteUpdate, but that uses the setup() function. I figured I'd try it out anyway with <script setup>:

<script setup>
import { onBeforeRouteUpdate } from 'vue-router'

onBeforeRouteUpdate(() => {
  console.log('onBeforeRouteUpdate')
})
</script>

However, this does not execute. The closest method I've tried that works is fetching the data in the router, using the beforeEnter guard, and setting the data onto the meta property, which can then get accessed on the route instance in the ponent:

beforeEnter: (to, from, next) => {
  fetch('https://pokeapi.co/api/v2/pokemon/ditto')
    .then(res => res.json())
    .then(res => {
    to.meta.pokemon = res;

    next();
  });
}

But with this, which is noted in the documentation, beforeEnter only triggers when entering the route. Params changes will not retrigger this, meaning that I'd have to set up a watcher on the route in the ponent anyway. I might as well just have had all this logic in the ponent itself.

I just can't seem to find a good way to do this, but I might have overlooked something. If anyone has some pointers or advice, I'd appreciate it. Thanks in advance.

Share Improve this question edited Oct 24, 2022 at 0:24 kissu 47k16 gold badges90 silver badges189 bronze badges asked Oct 23, 2022 at 22:57 kenshin9kenshin9 2,3754 gold badges29 silver badges42 bronze badges 7
  • Do you want block the render/navigation of the page until your data is resolved or not? – kissu Commented Oct 23, 2022 at 23:47
  • Yeah, that's correct. I basically want it to function like a typical webpage that doesn't use async requests and skeleton screens. – kenshin9 Commented Oct 23, 2022 at 23:48
  • As someone zealous about render times, I would encourage that you do not do this :) rendering something, even something unfinished, is always preferable to blocking the app. – Leland Commented Oct 24, 2022 at 0:29
  • @Leland yep, feels faster for the users for sure. But it's also quite more work. – kissu Commented Oct 24, 2022 at 0:47
  • 1 Yeah, I get the feeling skeletons are what's preferred today. But as kissu mentioned, it does require more work, which requires more time (the real issue really). – kenshin9 Commented Oct 24, 2022 at 4:08
 |  Show 2 more ments

2 Answers 2

Reset to default 2

There is a solution - using top level await - https://vuejs/api/sfc-script-setup.html#top-level-await

Just wrap your RouterView ponent in a Suspense ponent like shown here - https://vuejs/guide/built-ins/suspense.html#bining-with-other-ponents (don't use the ponents you don't need)

The only caveat is that the 'loading screen' will be visible on the initial request.

I made a little demo for you so you can try it out - https://github./ileue/vue-top-level-await-demo

First off, beforeRouteUpdate is only triggered when updating the actual route but not going to another ponent/page as officially told here.

An example on what could trigger that lifecycle hook would be

<button @click="$router.push({ hash: `#${Math.floor(Math.random() * 10)}` })">
  random hash
</button>

onBeforeRouteLeave perfectly works tho, as you can expect, when moving from page to page.

As for the initial question, you could implement some kind of router middleware like Nuxt does it. That way, you could await an HTTP call and only then allow for an actual navigation. Hence creating a block navigation effect pretty much.

I'm not sure on how to write that with Composition API, but I know that it perfectly works with Options API (quite some blog posts available). setup by itself behaving in it's own life-cycly way, I guess quite some things are rather tricky.

TLDR: a good ol' router middleware + wrapper around your pages (like a layout) is the perfect bo in your case IMO. There, you could set a single watcher for quite a lot of pages at the same time.

But everything depends on how you want to organize yourself and structure your code of course.


Skeleton screens bring a sense of being faster than something blocking but overall, you could also use prefetch (ing with Nuxt too by default) to get some hints and potentially load some assets even before they are needed. (+ other tricks in the same domain to speed up your network requests)

发布评论

评论列表(0)

  1. 暂无评论