網(wǎng)站做視頻在線觀看網(wǎng)址網(wǎng)站開發(fā)合同
原文鏈接
CSDN 的排版/樣式可能有問題,去我的博客查看原文系列吧,覺得有用的話,給我的庫點個star,關(guān)注一下吧?
上一篇【Next.js 項目實戰(zhàn)系列】03-查看 Issue
修改 Issue
添加修改 Button?
本節(jié)代碼鏈接
安裝 Radix UI 的?Radix Ui Icons
npm i @radix-ui/react-icons
# /app/issues/[id]/page.tsx...const IssueDeatilPage = async ({ params }: Props) => {...return (// 添加一個 Grid 以分列顯示,設(shè)置 initial 為 1,在移動設(shè)備為每頁 1 欄,平板以上則 2 欄<Grid columns={{ initial: "1", md: "2" }} gap="5"><Box><Heading as="h2">{issue.title}</Heading>...</Box>{/*添加一個 Button 用于編輯*/}
+ <Box>
+ <Button>
+ <Pencil2Icon />
+ <Link href={`/issues/${issue.id}/edit`}>Edit Issue</Link>
+ </Button>
+ </Box></Grid>);};export default IssueDeatilPage;
Single Responsbility Principle?
本節(jié)代碼鏈接
Software entities should have a single responsibility
重構(gòu)?/app/issues/[id]/page.tsx
?以應(yīng)用 SRP
- page.tsx
- IssueDetails.tsx
- EditIssueButton.tsx
# /app/issues/[id]/page.tsximport prisma from "@/prisma/client";
import { Box, Grid } from "@radix-ui/themes";
import { notFound } from "next/navigation";
import EditIssueButton from "./EditIssueButton";
import IssueDetails from "./IssueDetails";interface Props {params: { id: string };
}
const IssueDeatilPage = async ({ params }: Props) => {const issue = await prisma.issue.findUnique({where: { id: parseInt(params.id) },});if (!issue) notFound();return (<Grid columns={{ initial: "1", md: "2" }} gap="5"><Box><IssueDetails issue={issue} /></Box><Box><EditIssueButton issueId={issue.id} /></Box></Grid>);
};
export default IssueDeatilPage;
# /app/issues/[id]/IssueDetails.tsximport { IssueStatusBadge } from "@/app/components";
import { Issue } from "@prisma/client";
import { Card, Flex, Heading, Text } from "@radix-ui/themes";
import ReactMarkdown from "react-markdown";const IssueDetails = ({ issue }: { issue: Issue }) => {return (<><Heading as="h2">{issue.title}</Heading><Flex gap="3" my="5"><IssueStatusBadge status={issue.status}></IssueStatusBadge><Text>{issue.createdAt.toDateString()}</Text></Flex><Card className="prose"><ReactMarkdown>{issue.description}</ReactMarkdown></Card></>);
};
export default IssueDetails;
# /app/issues/[id]/EditIssueButton.tsximport { Pencil2Icon } from "@radix-ui/react-icons";
import { Button } from "@radix-ui/themes";
import Link from "next/link";const EditIssueButton = ({ issueId }: { issueId: number }) => {return (<Button><Pencil2Icon /><Link href={`/issues/${issueId}/edit`}>Edit Issue</Link></Button>);
};
export default EditIssueButton;
修改 Issue?
頁面?
本節(jié)代碼鏈接
我們可以像這樣構(gòu)建文件結(jié)構(gòu),在?Issue
?目錄下創(chuàng)建?_components
?以放置該目錄下需要重復(fù)使用的組件,文件夾名前添加下劃線就可以把這個文件夾從路由中移除
└─issues│ IssueActions.tsx│ loading.tsx│ page.tsx│├─new│ loading.tsx│ page.tsx│├─[id]│ │ EditIssueButton.tsx│ │ IssueDetails.tsx│ │ loading.tsx│ │ page.tsx│ ││ └─Edit│ page.tsx│└─_componentsIssueForm.tsx
將之前的 new/page.tsx 封裝為一個組件,并添加一個可選參數(shù),以初始化
# /app/issues/_components/IssueForm.tsx...
+ import { Issue } from "@prisma/client";...// 添加一個可選參數(shù) issue 類型為之前 prisma 中的 Issue
- const IssueForm = () => {
+ const IssueForm = ({ issue }: { issue?: Issue }) => {...return (<div className="max-w-xl prose">...<TextField.Root><TextField.Input// 將該字段初始化為 issue.title (若傳入 issue)
+ defaultValue={issue?.title}placeholder="Title"{...register("title")}/></TextField.Root><ErrorMessage>{errors.title?.message}</ErrorMessage><Controller// 將該字段初始化為 issue.description (若傳入 issue)
+ defaultValue={issue?.description}name="description"control={control}render={({ field }) => (<SimpleMDE placeholder="Description" {...field} />)}/>...</div>);};export default IssueForm;
API?
本節(jié)代碼鏈接
# /app/api/issues/[id]/route.tsximport { issueSchema } from "@/app/validationSchema";
import { NextRequest, NextResponse } from "next/server";
import prisma from "@/prisma/client";export async function PATCH(request: NextRequest,{ params }: { params: { id: string } }
) {const body = await request.json();const validation = issueSchema.safeParse(body);if (!validation.success)return NextResponse.json(validation.error.format(), { status: 400 });const issue = await prisma.issue.findUnique({where: { id: parseInt(params.id) },});if (!issue)return NextResponse.json({ error: "Invalid Issue" }, { status: 404 });const updatedIssue = await prisma.issue.update({where: { id: issue.id },data: { title: body.title, description: body.description },});return NextResponse.json(updatedIssue, { status: 200 });
}
連接?
本節(jié)代碼鏈接
# /app/issues/_components/IssueForm.tsxconst IssueForm = ({ issue }: { issue?: Issue }) => {...return (...<formclassName="space-y-3"onSubmit={handleSubmit(async (data) => {try {setSubmitting(true);// 判斷是否傳入了 issue,若有傳入則是 Update,若無則是 new
+ if (issue) await axios.patch("/api/issues/" + issue.id, data);
- await axios.post("/api/issues", data);
+ else await axios.post("/api/issues", data);router.push("/issues");} ...})}>...<Button disabled={isSubmitting}>
+ {issue ? "Update Issue" : "Submit New Issue"}{" "}{isSubmitting && <Spinner />}</Button></form>...);};export default IssueForm;
Caching?
本節(jié)代碼鏈接
NextJS Route Segment Config
- Data Cache:
- When we fetch data using fetch()
- Stored in the file system
- Permanent unitl we?redeploy
fetch(".",{cache: "no-store"})
fetch(".",{revalidata: 3600})
- Full Route Cache
- Used to store the output of statically renderd routes
- Router Cache (Client-side Cache)
- To store the payload of pages in browser
- Lasts for a session
- Gets refreshed when we reload
提升 Loading 體驗?
本節(jié)代碼鏈接
由于我們要在多個地方用到 IssueForm 的 Skeleton,我們可以將其封裝到一個組件里,然后在需要的地方調(diào)用。其次,對于靜態(tài)的頁面可以直接使用 loading.tsx,但是對于需要用到 dynamic 函數(shù)的頁面,應(yīng)該用另一種方法
- IssueFormSkeleton.tsx
- page.tsx
- loading.tsx
# /app/issues/_components/IssueFormSkeleton.tsximport { Skeleton } from "@/app/components";
import { Box } from "@radix-ui/themes";const IssueFormSkeleton = () => {return (<Box className="max-w-xl"><Skeleton height="2rem" /><Skeleton height="20rem" /></Box>);
};
export default IssueFormSkeleton;
# /app/issues/[id]/edit/page.tsximport prisma from "@/prisma/client";
import dynamic from "next/dynamic";
import { notFound } from "next/navigation";
import IssueFormSkeleton from "./loading";const IssueForm = dynamic(() => import("@/app/issues/_components/IssueForm"), {ssr: false,loading: () => <IssueFormSkeleton />,
});interface Props {params: { id: string };
}const EditIssuePage = async ({ params }: Props) => {const issue = await prisma.issue.findUnique({where: { id: parseInt(params.id) },});if (!issue) notFound();return <IssueForm issue={issue} />;
};
export default EditIssuePage;
# /app/issues/[id]/edit/loading.tsximport IssueFormSkeleton from "@/app/issues/_components/IssueFormSkeleton";
export default IssueFormSkeleton;
CSDN 的排版/樣式可能有問題,去我的博客查看原文系列吧,覺得有用的話,給我的庫點個star,關(guān)注一下吧??
下一篇講刪除 Issue