【Next.js 项目实战系列】04-修改 Issue

原文链接

CSDN 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话,给我的库点个star,关注一下吧 

上一篇【Next.js 项目实战系列】03-查看 Issue

修改 Issue

添加修改 Button​

本节代码链接

安装 Radix UI 的 Radix Ui Icons

npm i @radix-ui/react-icons
# /app/issues/[id]/page.tsx...const IssueDeatilPage = async ({ params }: Props) => {...return (// 添加一个 Grid 以分列显示,设置 initial 为 1,在移动设备为每页 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​

本节代码链接

Software entities should have a single responsibility

重构 /app/issues/[id]/page.tsx 以应用 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​

页面​

本节代码链接

我们可以像这样构建文件结构,在 Issue 目录下创建 _components 以放置该目录下需要重复使用的组件,文件夹名前添加下划线就可以把这个文件夹从路由中移除

└─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 封装为一个组件,并添加一个可选参数,以初始化

# /app/issues/_components/IssueForm.tsx...
+ import { Issue } from "@prisma/client";...// 添加一个可选参数 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​

本节代码链接

# /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 });
}

连接​

本节代码链接

# /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​

本节代码链接

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 体验​

本节代码链接

由于我们要在多个地方用到 IssueForm 的 Skeleton,我们可以将其封装到一个组件里,然后在需要的地方调用。其次,对于静态的页面可以直接使用 loading.tsx,但是对于需要用到 dynamic 函数的页面,应该用另一种方法

  • 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,关注一下吧  

下一篇讲删除 Issue

下一篇【Next.js 项目实战系列】05-删除 Issue

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/56983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLO11 目标检测 | 导出ONNX模型 | ONNX模型推理

本文分享YOLO11中&#xff0c;从xxx.pt权重文件转为.onnx文件&#xff0c;然后使用.onnx文件&#xff0c;进行目标检测任务的模型推理。 用ONNX模型推理&#xff0c;便于算法到开发板或芯片的部署。 备注&#xff1a;本文是使用Python&#xff0c;编写ONNX模型推理代码的 目…

【Vercel】Vercel静态部署踩坑

背景 在现代的软件开发中&#xff0c;自动化部署是一个不可或缺的环节。Vercel作为一个流行的前端部署平台&#xff0c;提供了与GitHub的无缝集成&#xff0c;使得开发者能够在每次提交代码后自动触发部署流程。然而&#xff0c;自动化部署过程中可能会遇到一些挑战&#xff0…

全网免费的文献调研方法以及获取外网最新论文、代码和翻译pdf论文的方法(适用于硕士、博士、科研)

1. 文献调研 学术搜索引擎(十分推荐前三个&#xff0c;超有用)&#xff1a;使用 Google Scholar(https://scholar.google.com/)(https://scholar.google.com.tw/)(巨人学术搜索‬‬)、&#xff08;三个都可以&#xff0c;镜像网站&#xff09; arXiv(https://arxiv.org/)、&am…

qt页面设计

1. Designer 设计师&#xff08;掌握&#xff09; Designer是Qt内置的一款界面设计程序&#xff0c;设计的界面文件为.ui格式。 C程序员通常不会单独启动Designer&#xff0c;如果要在项目中使用Designer程序&#xff0c;只需要在新建项目时&#xff0c;勾选“创建界面文件”选…

学习C语言(25)

整理今天的学习内容 预处理详解 1.预定义符号 C语言设置了一些预定义符号&#xff0c;可以直接使用&#xff0c;预定义符号是在预处理期间处理的 __FILE__&#xff08;进行编译的源文件&#xff09; __LINE__ &#xff08;文件当前的行号&#xff09; __DATE__&#xff08…

Visual Studio 2022安OpenCV可视化工具image watch

1. 打开 VS2022 &#xff0c;扩展 -管理扩展 2. 搜索 Image Watch 关闭VS2022 后 安装 打开视图、调出 Image Watch 窗口 测试代码&#xff1a; #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.…

分布式系统中的Dapper与Twitter Zipkin:链路追踪技术的实现与应用

目录 一、什么是链路追踪&#xff1f; 二、核心思想Dapper &#xff08;一&#xff09;Dapper链路追踪基本概念概要 &#xff08;二&#xff09;Trace、Span、Annotations Trace Span Annotation 案例说明 &#xff08;三&#xff09;带内数据与带外数据 带外数据 带…

【Linux】进程间通信---匿名管道、命名管道(超详解)

目录 匿名管道 管道的创建&#xff1a; 创建子进程&#xff1a; 关闭不需要的fd: 发送消息&#xff1a; 管道的5种特征&#xff1a; 管道的4种情况&#xff1a; 命名管道 创建命名管道&#xff1a; 删除命名管道&#xff1a; 手写命名管道&#xff1a; 完整代码&am…

多线程(七):单例模式指令重排序

目录 1. 单例模式 1.1 饿汉模式 1.2 懒汉模式 2. 懒汉模式下的问题 2.1 线程安全问题 2.2 如何解决 --- 加锁 2.3 加锁引入的新问题 --- 性能问题 2.4 指令重排序问题 2.4.1 指令重排序 2.4.2 指令重排序引发的问题 1. 单例模式 单例模式, 是设计模式中最典型的一种模…

Vision China 2024 | 移远通信以一体化的AI训练及部署能力,引领3C电子制造智能升级

10月14日&#xff0c;由机器视觉产业联盟(CMVU)主办的中国机器视觉展(Vision China)在深圳国际会展中心盛大开幕。作为全球领先的物联网整体解决方案供应商&#xff0c;移远通信应邀参加展会首日举办的“智造引领数质并进”3C电子制造自动化与数字化论坛。 论坛上&#xff0c;移…

PostgreSQL学习笔记:PostgreSQL vs MySQL

PostgreSQL 和 MySQL 都是广泛使用的关系型数据库管理系统&#xff0c;它们有以下一些对比&#xff1a; 一、功能特性 1. 数据类型支持 PostgreSQL&#xff1a;支持丰富的数据类型&#xff0c;包括数组、JSON、JSONB、范围类型、几何类型等。对于复杂数据结构的存储和处理非…

rancher安装并快速部署k8s 管理集群工具

主机准备 准备4台主机 3台用于k8s集群 &#xff0c;1台用于rancher 每台服务器新增配置文件 vi etc/sysctl.confnet.ipv4.ip_forward 1 刷新生效 sysctl –p 安装docker 安装的时候可以去github上检索rancher看看最新版本适配那个版本的docker&#xff0c;这里安装23.0.1…

酸碱PH值与浓度关系

1. 硫酸百分比浓度是指溶液中硫酸的质量占溶液总质量的百分比。‌ 例如&#xff0c;如果100克溶液中含有98克的硫酸&#xff0c;那么硫酸的百分比浓度为98% 2. 1mol/L硫酸对应百分比浓度多少&#xff1f;答&#xff1a;硫酸的质量分数98&#xff0c;1mol/L硫酸98g/L9.8%的硫酸…

RNN,LSTM,GRU的区别和联系? RNN的梯度消失问题?如何解决?

RNN&#xff0c;LSTM&#xff0c;GRU的区别和联系? RNN&#xff08;Recurrent Neural Network&#xff09;、LSTM&#xff08;Long Short-Term Memory&#xff09;和GRU&#xff08;Gated Recurrent Unit&#xff09;都是用于处理序列数据的神经网络模型&#xff0c;它们之间…

动态规划:17.简单多状态 dp 问题_买卖股票的最佳时机III_C++

题目链接&#xff1a; 一、题目解析 题目&#xff1a;123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; 解析&#xff1a; 拿示例1举例&#xff1a; 我们可以如图所示买入卖出股票&#xff0c;以求得最大利润&#xff0c;并且交易次数不超过2次 拿示…

二百六十九、Kettle——ClickHouse清洗ODS层原始数据增量导入到DWD层表中

一、目的 清洗ClickHouse的ODS层原始数据&#xff0c;增量导入到DWD层表中 二、实施步骤 2.1 newtime select( select create_time from hurys_jw.dwd_statistics order by create_time desc limit 1) as create_time 2.2 替换NULL值 2.3 clickhouse输入 2.4 字段选择 2.5 …

Git的原理和使用(三)

1. 分支管理 1.1 合并模式 1.1.1 fast forward模式 git log --graph --abbrev-commit 1.1.2 no-ff模式 合并出现问题后需要进行手动修改&#xff1a; 如下图所示&#xff1a; 1.1.3 不使用no-ff模式 git merge --no-ff -m "merge dev2" dev2 1.2 分⽀策略 在实际开…

多IP访问多网段实验

文章目录 多IP访问多网段实验 多IP访问多网段实验 在当前主机配置多个IP地址&#xff0c;实现多IP访问多网段&#xff0c;记录所有命令及含义 1&#xff0c;环境搭建&#xff1a; [rootlocalhost ~]# mount /dev/sr1 /mnt # 设置ISO虚拟镜像文件文件挂载点&#xff0c;将…

数据分析和可视化python库orange简单使用方法

Orange 是一个基于 Python 的数据挖掘和机器学习库&#xff0c;它提供了一系列可视化工具和算法&#xff0c;用于数据分析、机器学习和数据可视化等任务。 一、主要特点 可视化界面&#xff1a;Orange 提供了直观的可视化界面&#xff0c;使得用户可以通过拖放操作构建数据分…

【python爬虫实战】爬取全年天气数据并做数据可视化分析!附源码

由于篇幅限制&#xff0c;无法展示完整代码&#xff0c;需要的朋友可在下方获取&#xff01;100%免费。 一、主题式网络爬虫设计方案 1. 主题式网络爬虫名称&#xff1a;天气预报爬取数据与可视化数据 2. 主题式网络爬虫爬取的内容与数据特征分析&#xff1a; - 爬取内容&am…