5

假设我有一个blog加载所有博客文章的完整数组的路由。个人博客文章位于blog/[postId]。是否有一种 Sapper 惯用的方式将单个帖子的数据从blogto 传递blog/[postId]

本质上,如果你在blog我想预加载显示的代码blog/[postId]。然后,当您单击指向 的链接时blog/[postId],立即导航并显示来自 的数据blog。但是当然,如​​果您直接导航到blog/[postId]thenpreload()仍然应该被调用。

prefetch不完全这样做,因为这仍然需要网络请求。我还尝试了一个预加载,它检查一个商店并且除非它是空的,否则不会发出网络请求,但你不能在<script context="module">.

4

1 回答 1

2

感谢@three的评论让我找到了答案。

如果路由或_layout组件导出preload(),它总是在导航时被调用。所以我最终通过将获取的数据存储在第二个参数 to 中来做到preload()这一点,这通常被称为session并且似乎在所有组件之间共享。而且我只this.fetch()在数据不存在时才打电话。

<!-- blog/index.svelte -->
<script context="module">
  export async function preload (page, session) {
    let {posts} = session;
    if (undefined === posts) {
      const response = await this.fetch('blog/posts.json');
      posts = await response.json();
      session.posts = posts
    }

    return {posts}
  }
</script>

<script>
  export let posts;
</script>

{#each posts as post}
  <!-- ... -->
{/each}

然后[slug].svelte检查session.posts您要查找的帖子,如果不存在,请加载它。

<!-- blog/[slug].svelte -->
<script context="module">
  export async function preload (page, session) {
    const {slug} = page.params
    const {posts} = session
    let post

    if (undefined === posts) {
      const response = await this.fetch(`blog/${slug}.json`)
      post = await response.json()
    } else {
      post = posts.find(p => p.slug === slug)
    }

    if (undefined === post) {
      this.error(404, "Sorry we couldn\'t find that post")
    }

    return {post}
  }
</script>

<script>
  export let post
</script>

<!-- ... render post -->

现在导航是即时的。为了获得最终的稳健性,如果数据过时(比如超过 5 分钟,无论如何),您可以添加检查以重新加载。

编辑

本质上,您实际上并不需要使用会话。如果您只想使session参数preload(page, session)不是,undefined您可以在以下位置使用它server.js

sapper.middleware({
  // Define session parameter as an empty object
  session: (req, res) => ({})
})
于 2020-02-15T05:03:07.997 回答