如何在Next JS Blog中实现Previous Post和Next Post?

时间:2019-02-21 15:24:01

标签: javascript reactjs next.js

我要转到特定博客文章的上一篇和下一篇文章。

考虑一下,这个盖茨比示例-https://gatsby-starter-blog-demo.netlify.com/my-second-post/

它在页面底部有2个链接-

←Hello World 是上一篇文章,新起点→是下一篇文章

要动态使用此功能,我需要访问帖子的内容,但我将如何获得它?由于使用了GraphQL,在盖兹比中很简单。

但是,在下一步中,我仅需使用preval hack即可获得帖子。我将如何获得,以便可以在自己的特定博客中实现“上一篇”和“下一篇”?

即使Next JS's own blog也没有“下一篇文章”和“上一篇文章”链接。

签出any post on Next JS's Blog,您会发现一个返回博客按钮,但没有上一个帖子或下一个帖子按钮。

4 个答案:

答案 0 :(得分:1)

分页非常简单。您可以使用static async getInitialProps方法从查询中获取请求的页面。

然后,您可以将buttonRouter.push一起使用进行强制路由,或者将Link进行声明式路由。

class PaginationTest extends React.Component {
  static async getInitialProps ({query: {page = 1}}) {
   const data = await fetchPage(page)
   return {
     page: parseInt(page, 10),
     data
   }
  }

  render () {
    return (
      <div>
        // render data
        <button 
          onClick={() => Router.push(`/page=${this.props.page + 1}`)} 
          disabled={this.props.page <= 1}
        >Next Button</button>
        <Link href={`/page=${this.props.page + 1}`}>
          <a>Next Link</a>
        </Link>
      </div>
    )
  }
}

Here is a working codesandbox: https://codesandbox.io/s/6w3k5yzqmn

答案 1 :(得分:1)

因为要生成一个静态站点,所以我假设您只关心从Next.JS的服务器端解决这个问题。为此,您基本上需要编写一个名为getNextPost(current)的函数,该函数接收您当前的帖子(只是文件名或完整的对象),并在您的posts目录中扫描下一个帖子。对于Next.JS的服务器端,您位于Node中,因此您可以仅使用fs包来扫描文件系统。

理想情况下,这意味着每个文件名都应带有时间戳或类似的前缀(例如2019-02-22_13-45-53-my-second-post.html),这样您就可以使用简单的排序来确定下一个帖子是什么。否则,您实际上需要解析每个发布文件,以这种方式提取日期信息(我相信这就是盖茨比的工作方式,它肯定是雨果所做的事情。)

无论哪种方式,我建议一次将所有发布文件解析到内存缓存中,这样就不必每次都扫描发布目录。

答案 2 :(得分:0)

首先,您必须问自己“上一个帖子”和“下一个帖子”是什么意思以及如何找到这些帖子。
你能表达出来吗?回答此问题将解决您的大部分问题,而不是与Next.js相关的问题。

  • 如果您使用的是增量ID,答案可能是“我以前的帖子是我当前帖子的ID减1”和下一个帖子的“加1”。
  • 否则,答案可能是“我以前的帖子是按created_at日期在当前帖子之前的帖子”

一旦您澄清了这一点,“我如何添加上一个和下一个帖子链接”问题的答案就是mrvdot和lipp提供的内容的组合。

创建一个getNextPostgetPreviousPost函数。假设您具有增量ID,一个简单(但不可靠)的示例将是:

const getPreviousPost = currentPostId => getPost(currentPostId - 1)
const getNextPost = currentPostId => getPost(currentPostId + 1)

一旦有了这些信息,就可以在“帖子”组件的getInitialProps中查询除当前帖子之外的上一篇和下一篇帖子

class Post extends React.Component {
  static async getInitialProps ({id}) {
    const post = await getPost(id)
    const previousPost = await getPreviousPost(id)
    const nextPost = await getNextPost(id)

    return {
      post,
      previousPost,
      nextPost,
    }
  }

  getPreviousPost = currentPostId => getPost(currentPostId - 1)

  getNextPost = currentPostId => getPost(currentPostId + 1)

  render ({post, previousPost, nextPost}) {
    return (
      <div>
        <h1>{post.title}</h1>
        <p>{post.content}</p>

        <Link href={previousPost.url}><a>Previous post</a></Link>
        <Link href={nextPost.url}><a>Next post</a></Link>
      </div>
    )
  }
}

或者类似的东西。这有道理吗?

答案 3 :(得分:0)

我遇到了同样的问题。我有一个函数可以获取所有帖子标题(即 slug 和 frontmatter),并且我有当前帖子的 slug。为了找到上一篇和下一篇文章,我写了这段打字稿:

export interface AdjacentPosts {
    previous: { slug: string, title: string } | null,
    next: { slug: string, title: string } | null,
};

export function getAdjacentPosts(slug: string): AdjacentPosts {
    const allPostHeaders = getAllPostHeaders();
    const postIndex = allPostHeaders.findIndex(postHeader => postHeader?.slug === slug);
    return {
        previous: postIndex <= 0
            ? null
            : { slug: allPostHeaders[postIndex - 1]!.slug, title: allPostHeaders[postIndex - 1]!.frontmatter.title },
        next: postIndex >= allPostHeaders.length - 1
            ? null
            : { slug: allPostHeaders[postIndex + 1]!.slug, title: allPostHeaders[postIndex + 1]!.frontmatter.title }
    };
}

我在 [slug].tsx 中使用此函数:

export const getStaticPaths: GetStaticPaths = async () => {
    const slugs = getAllPostSlugs().concat(getAllPageSlugs());
    return {
        paths: slugs.map(slug => ({ params: { slug }, })),
        fallback: false,
    }
}

export const getStaticProps: GetStaticProps = async ({ params }) => {
    if (!params) {
        return { props: {} };
    }

    const post = getPostBySlug(params.slug as string)
    if (post) {
        return {
            props: {
                post,
                isPost: true,
                adjacentPosts: getAdjacentPosts(post.slug)
            }
        }
    }

    const page = getPageBySlug(params.slug as string)
    return { props: { post: page!, isPost: false, adjacentPosts: null } };
}

export default function PostBody(props: { post: PostData, isPost: boolean, adjacentPosts: AdjacentPosts | null }) {
    const { post, isPost } = props;
    const previous = props.adjacentPosts?.previous;
    const next = props.adjacentPosts?.next;

    return (
        <React.Fragment>
           ...the blog post itself, and then this:
           <nav className="post-navigation" role="navigation" aria-label="Posts">
                <h2 className="sr-only">Post navigation</h2>
                <div className="grid sm:grid-cols-1 md:grid-cols-2 gap-6">
                    <div className="nav-previous">
                        {previous && (
                            <Link href={previous.slug}>
                                <a className="flex flex-col text-left" rel="prev">
                                    <span className="text-base mb-2">Previous: </span>
                                    <span className="sr-only">Previous post:</span>
                                    <span className="text-primary-500 leading-6">
                                        {previous.title}
                                    </span>
                                </a>
                            </Link>
                        )}
                    </div>
                    <div className="nav-next">
                        {next && (
                            <Link href={next.slug}>
                                <a className="flex flex-col text-right"
                                   rel="next">
                                    <span className="text-base mb-2">Next: </span>
                                    <span className="sr-only">Next post:</span>
                                    <span className="text-primary-500 leading-6">
                                        {next.title}
                                    </span>
                                </a>
                            </Link>
                        )}
                    </div>
                </div>
            </nav>
        </React.Fragment>
    )
}

祝你好运!