我正在构建一个科学博客,其中帖子的 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 中的主题中没有更多项目时,如何禁用链接?
要解决
${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'
。