在 NextJS 中使用 JSON 文件作为分页

问题描述 投票:0回答:1

我正在构建一个科学博客,其中帖子的 URL 存储在静态 JSON 文件中。

ScienteTopics.json-

[
  {
    "Subject": "Mathematics",
    "chapters": "mathematics",
    "contentList": [
      {
        "content": "Algebra",
        "url": "algebra-content-url"
      },
      {
        "content": "Trigonometry",
        "url": "trigonometry-content-url"
      },
      {
        "content": "Geometry",
        "url": "geometry-content-url"
      }
    ]
  },
  {
    "Subject": "Physics",
    "chapters": "physics",
    "contentList": [
      {
        "content": "Newton's 1st law",
        "url": "newtons-fisrt-law-url"
      },
      {
        "content": "Newton's 2nd law",
        "url": "newtons-second-law-url"
      },
      {
        "content": "Newton's 3rd law ",
        "url": "newtons-third-law-url"
      }
    ]
  }
]

我想在单个帖子页面上添加分页。 这个答案非常适合ReactJS,但唯一的问题是

useEffect
钩子使用“客户端”,这与NextJS的
generateStaticParams()
冲突。我修改了代码-

page.tsx-


import React, { useMemo } from 'react'
import fs from "fs"

import Link from "next/link"
import Markdown from "react-markdown"
import rehypeKatex from "rehype-katex"
import remarkMath from "remark-math"
import rehypeRaw from "rehype-raw"
import matter from "gray-matter"
import 'katex/dist/katex.min.css'

import ScienceTopics from '@/app/(subjects)/mathematicalphysics/ScienteTopics.json'
import path from "path"

import { Metadata, ResolvingMetadata } from "next"
import { notFound, useSearchParams } from "next/navigation"



const allPosts = ScienceTopics.flatMap(({ Subject, chapters, contentList }) =>
contentList.map((topics) => ({

    subjectName: Subject,
    subjectId: chapters,
    ...topics,

  })),
);


const folder = path.join(process.cwd(), 'src/ScienceTopics');// put it outside of app folder

const getPostContent = (chapterID:string, postID: string) => {
  
  const file = `${folder}/${chapterID}/${postID}.md`;

  if (!file) {
    notFound();
  }
  const content = fs.readFileSync(file, "utf8");
  const matterResult = matter(content);
  // return matterResult;
  return {
    title: matterResult.data.title,
    desc: matterResult.data.metaDesc,
    content: matterResult.content,
    img: matterResult.data.ImageUrl
  }
};






// generates static pages 
export async function generateStaticParams() {
  return allPosts.map((post) => ({
    chapterID: post.sectionId,
    postID: post.url

  }))
}


interface Post {
  sectionId: string;
  title: string;
  url: string;
}

interface Pagination {
  prev?: string;
  post?: Post;
  next?: string;

}
const ScienceBlogPage = ({params}:{params:any) => {
  
  
  //gets ids from url
  
  const postID = params.postID;
  // calculate prev/next page URLs
  const { prev, next, post } = useMemo<Pagination>(() => {
    const postIndex = allPosts.findIndex(({ url }) => url === postID);

    return {
      prev: allPosts[postIndex - 1]?.url,
      post: allPosts[postIndex],
      next: allPosts[postIndex + 1]?.url
    };
  }, [postID]);



  if(!post) {
    return null;
  }
  const curr_post = getPostContent(`${post.subjectId}`,`${post.url}`)
  
  return (

    <>

      <h1>{curr_post.title}</h1>
      <hr className="my-6 border border-dashed bg-sky-600 h-0.5" />
      <article lang="bn" className="prose lg:prose-xl">
        <Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex, rehypeRaw]}>
          {curr_post.content}</Markdown>
      
      </article>
     <Link className="float-left text-teal-600" aria-disabled={!prev} href={`${prev}`}>prev</Link>
     <Link className="float-right text-teal-600" aria-disabled={!next} href={`${next}`}>next</Link>
    </>

  )
}

export default ScienceBlogPage



虽然

${post.url}
正确更新,但
${post.subjectId}
也不会更新,链接在结束时会尝试转到“url/undefined”。

${post.subjectId}
到达 JSON 上的“contentList 数组”末尾时,如何更新它的值?例如,当它显示完数学下的所有内容后,该值将更改为物理等等。

当使用 NextJS 的 JSON 中的主题中没有更多项目时,如何禁用链接?

javascript reactjs node.js next.js
1个回答
0
投票

要解决

${post.subjectId}
不更新以及链接尝试转到
'url/undefined'
的问题,您需要处理不同主题之间的转换。当
postIndex
到达当前主题
contentList
的末尾时,您应该切换到下一个主题。

以下是如何修改代码来实现此目的:

const ScienceBlogPage = ({ params }: { params: any }) => {
  // gets ids from url
  const postID = params.postID;

  // calculate prev/next page URLs and switch subjects
  const { prev, next, post, switchSubject } = useMemo<Pagination>(() => {
    const postIndex = allPosts.findIndex(({ url }) => url === postID);

    if (postIndex === -1) {
      return {};
    }

    const currentPost = allPosts[postIndex];
    const isLastPostInSubject =
      postIndex === allPosts.length - 1 ||
      allPosts[postIndex + 1]?.subjectId !== currentPost.subjectId;

    return {
      prev: allPosts[postIndex - 1]?.url,
      post: currentPost,
      next: isLastPostInSubject ? null : allPosts[postIndex + 1]?.url,
      switchSubject: isLastPostInSubject,
    };
  }, [postID]);

  if (!post) {
    return null;
  }

  const curr_post = getPostContent(`${post.subjectId}`, `${post.url}`);

  return (
    <>
      <h1>{curr_post.title}</h1>
      <hr className="my-6 border border-dashed bg-sky-600 h-0.5" />
      <article lang="bn" className="prose lg:prose-xl">
        <Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex, rehypeRaw]}>
          {curr_post.content}
        </Markdown>
      </article>
      <Link
        className="float-left text-teal-600"
        aria-disabled={!prev}
        href={prev ? `/${post.subjectId}/${prev}` : ''}
      >
        prev
      </Link>
      <Link
        className="float-right text-teal-600"
        aria-disabled={!next}
        href={next ? `/${post.subjectId}/${next}` : ''}
      >
        next
      </Link>
      {switchSubject && (
        <div>
          {/* Render something to indicate that you're switching to the next subject */}
          Switching to the next subject: {allPosts[postIndex + 1]?.subjectId}
        </div>
      )}
    </>
  );
};

在此修改后的代码中,

switchSubject
变量用于确定下一篇文章是否属于不同的主题。如果是这样,您可以渲染一些内容来表明您正在切换到下一个主题。此外,下一个和上一个链接的
href
已更新为包含
subjectId
。这应该可以防止链接尝试转到
'url/undefined'

© www.soinside.com 2019 - 2024. All rights reserved.