Nuxt static 在推送新路由时不加载获取的状态

Nuxt static not loading fetched state when pushing new route

我正在按照此处所述使用 nuxt 生成完整的静态 Web 应用 https://nuxtjs.org/blog/going-full-static/#crazy-fast-static-applications

我还有一个小博客要作为静态站点加载,所以我使用获取挂钩从 api 加载数据。

async fetch() {
  this.posts = await fetch(`${this.baseApi}/posts`).then(res => res.json())
},

当我生成(npm run generate)时,获取的状态在dist/assets/static内部正确生成,所以当直接访问/blog时,状态被正确加载并且数据正确显示. 但是,当我进入主页并使用

访问博客时
this.$router.push

或一个

<nuxt-link to="/blog">Blog</nuxt-link>

获取的状态没有加载,我必须再次调用 api,或者在 mounted() 钩子中再调用一次 this.$fetch()

我已经添加了一个

watch: {
  '$route.query': '$fetch'
}

到首页

我需要在使用导航时正确加载获取的状态我还缺少什么?

澄清

我没有遇到任何关于获取挂钩本身的问题,而是导航没有检索目标路线的状态。 甚至 HTML 也在那里 我需要页面获取目标路由的状态,当路由发生变化时,因为vue模板依赖它,所以如果没有加载,ui不会显示任何东西,我被迫手动调用获取挂钩

为了看得更清楚,这是直接访问 /blog 时我的开发工具的屏幕截图,请注意如何正确检索 state.js(它包含所有呈现的内容)

下面是我的devtools访问/的截图,然后使用nuxt-link或this.$router.push(同样的结果)

静态截图:

Blog.vue

<template>
  <b-container class="container blog">
    <b-row>
      <b-col lg="12" md="12" sm="12" cols="12" class="logo-col">
        <SbLogoSingle />
      </b-col>
    </b-row>
    <b-row v-if="$fetchState.pending" class="text-center">
      <b-spinner style="margin: auto"></b-spinner>
    </b-row>
    <b-row v-else>
      <b-col
        v-for="(post, idx) in posts.data"
        :key="idx"
        lg="4"
        md="4"
        sm="6"
        cols="12"
        class="blog-post-col"
      >
        <b-card
          v-if="post !== undefined"
          no-body
          class="shadow-lg blog-post-card"
          :img-src="post.media.url"
          img-top
        >
          <b-card-body class="text-left">
            <b-card-title>{{ replaceSlugByString(post.slug) }}</b-card-title>
            <b-card-text
              class="post-short-description"
              v-html="post.localizations[0].shortDescription"
            ></b-card-text>
          </b-card-body>
          <template #footer>
            <div class="text-left">
              <b-button class="apply-btn read-more-btn" @click="openBlogPost(idx)">Read more</b-button>
            </div>
          </template>
        </b-card>
      </b-col>
    </b-row>
  </b-container>
</template>

<script>
import { mapState } from 'vuex'

export default {
  data() {
    return {
      slug: 'test',
      posts: {},
      currentPage: 1,
      perPage: 12,
      pageIndex: 1,
      totalPages: 1,
    }
  },
  async fetch() {
    const response = await fetch(`${this.baseApi}/StaticPage`)
    const fetchedPosts = await response.json()

    this.posts = fetchedPosts
    // this.posts = await fetch(`${this.baseApi}/StaticPage`).then(res =>res.json())
  },
  computed: {
    ...mapState('modules/settings', ['baseApi']),
  },
  beforeMount() {
    this.$fetch() // i want to remove this because the pages are statically generated correctly, I'm only adding it to refresh the state. which can be retrieved as a separate js file when accessing the route directly
  },
  methods: {
    openBlogPost(idx) {
      const pageObject = this.posts.data[idx]
      this.$router.push({
        name: `blog-slug`,
        params: {
          slug: pageObject.slug,
          page: pageObject,
        },
      })
    },
    replaceSlugByString(slug) {
      return slug.replaceAll('-', ' ')
    },
  },
}
</script>

这是 slug.vue

的 pastebin

https://pastebin.com/DmJa9Mm1

编辑:

  • fetch() 钩子很好用,即使你第一次来到这个特定页面,它也会被触发
  • Vue devtools 可以帮助您找出是否有某些状态缺失或行为异常。
  • 静态文件夹中没有 状态这样的东西 因为状态根本不是静态变量或事物,它是动态的并且仅在运行时可用。
  • 这个答案可能会帮助您看到一个使用 JSONplaceholder 的工作示例(带有列表 + 详细信息页面):

尽量不要混用 async/awaitthen
所以,这种语法应该更适合。

async fetch() {
  const response = await fetch(`${this.baseApi}/posts`)
  const fetchedPosts = await response.json()
  console.log('posts', fetchedPosts)
  this.posts = fetchedPosts
},

然后,你可以通过devtools的网络选项卡进行调试,看看是否触发了。不过我觉得到时候应该没问题。


我刚刚写得更深入的这个答案也可以帮助更多地理解 fetch() 钩子:

使用 nuxt generate 使用 nuxt 生成静态网站时,您使用 fetch hook 加载一次数据,而无需在您的站点中再次加载它。

您可能会遇到这样一种情况,您有一个正确生成的 html 页面,但数据为空,即使您可以在 html 源中看到内容,而空数据会导致UI 不加载,并强制您重新点击 api(或手动调用 $fetch 挂钩),以重新加载您的状态(和您的 UI)

在这种情况下,将您的数据移动到商店,在我的情况下,我创建了一个新的 store/modules/blog.js 文件:

export const state = () => ({
   posts:[]
})
export const mutations = {
   SET_POSTS(state, posts) {
       state.posts = posts
   }
}

然后修改你的 fetch hook 为:

async fetch() {
    const response = await this.$axios.$get(`${this.baseApi}/posts`)
    this.$store.commit("modules/blog/SET_POSTS",response)
}

你可以把this.$axios丢掉,用fetch也没关系。

然后,在你 运行 npm run generate 之后,看看你的 dist/assets/static/<someid>/state.js 你会发现里面有主页的所有状态(我的主页不包括博客文章)所以我读了 modules:{blog:{posts:[]}... empty array

转到您的 dist/assets/static/<someid>/blog/state.js,您应该会在 modules:{blog:{posts:{success:am,code:an ... 中找到从 api 加载的所有帖子 还有一个dist/assets/static/<someid>/blog/payload.js

现在,当您访问您的主页时,当 <nuxt-link to='/blog'> 可见时将获取博客的 payload.js,并且您的状态将使用已获取的数据进行更新

现在,如果您直接访问 /blog,将在获取 payload.js 之前检索 state.js,您的状态将是最新的

这就是您创建一个小型静态博客的方式,而无需点击 API。希望这对您有所帮助。