当前位置: 首页 > news >正文

【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

相关文章:

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

原文链接 CSDN 的排版/样式可能有问题&#xff0c;去我的博客查看原文系列吧&#xff0c;觉得有用的话&#xff0c;给我的库点个star&#xff0c;关注一下吧 上一篇【Next.js 项目实战系列】03-查看 Issue 修改 Issue 添加修改 Button​ 本节代码链接 安装 Radix UI 的 Ra…...

【Linux】并行与并发(含时间片)

简单来说 并发&#xff1a;多个进程轮流使用同一个CPU&#xff0c;在逻辑层面上&#xff0c;一段时间内推进完成了多个进程 并行&#xff1a;机器中有多个CPU可以使用&#xff0c;在物理层面上&#xff0c;做到同一时间会有多个进程同时在运行 举个例子&#xff1a;一群人需要…...

【Flutter】页面布局:弹性布局(Flex)

在 Flutter 开发中&#xff0c;布局是非常重要的部分。布局系统允许开发者控制和管理界面上的组件如何排列和展示。弹性布局&#xff08;Flex&#xff09;是其中一个非常强大且常用的布局组件&#xff0c;它能够在水平方向或垂直方向上灵活调整子组件的空间分配比例。Row 和 Co…...

深入解析 Go 语言接口:多接口实现与接口组合的实际应用

文章目录 一、引言二、一个类型实现多个接口1. 定义多个接口2. 类型实现多个接口3. 使用多个接口 三、接口的组合1. 接口嵌套2. 实现复合接口 四、实际开发中的应用场景1. 多态与模块化设计2. 松耦合系统设计3. 测试与依赖注入4. 事件驱动架构中的应用 五、小结 一、引言 在 G…...

Eclipse——Java开发详解

Eclipse 1、配置JDK2、设置编译版本2.1、全局编译版本2.2、项目编译版本2.3、Web项目编译版本 3、设置工作目录4、创建Java项目5、配置Tomcat6、创建Web项目7、配置Maven8、创建Maven项目8.1、普通Maven项目8.2、Maven Web项目 9、创建SpringBoot项目10、设置字体11、设置代码提…...

练手小项目推荐

以下是一些练手项目推荐&#xff0c;我可以给你一些适合学生毕业设计的小项目建议&#xff0c;既可以锻炼技能&#xff0c;也能完成学术要求。以下是一些可行的毕业设计项目建议&#xff1a; 校园导航APP 功能&#xff1a;为校园内的新生和访客提供导航&#xff0c;标记教室、…...

一图秒懂色彩空间和色彩模型

色彩空间和色彩模型 想必学过图像处理或者摄影的小伙伴都知道这两个词&#xff0c;看了一些博客&#xff0c;发现很少有人把这两个概念说清楚的&#xff0c;大多数都是混在一起&#xff0c;色彩模型和色彩空间的概念混为一谈&#xff0c;很让人疑惑。   这里我们用一张图来解…...

控制Stable Diffusion生成质量的多种方法

在Stable Diffusion绘图中&#xff0c;控制AI生成图像的质量可以通过多种方法来实现。以下是几种常见的方法&#xff1a; 1. 从底模控制&#xff08;Checkpoint&#xff09; 使用不同的模型检查点&#xff08;Checkpoints&#xff09;可以显著影响生成图像的质量和细节。选择一…...

递归算法笔记

根据b站视频整理的 **视频地址&#xff1a;**https://www.bilibili.com/video/BV1S24y1p7iH/?spm_id_from333.788.videopod.sections&vd_source6335ddc7b30e1f4510569db5f2506f20 最常见的一个递归例子&#xff1a; 斐波那契数列&#xff1a;1&#xff0c;2&#xff0c;3…...

Android——发送彩信

跳转到相册选择图片 btn_jump.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View view) {// 跳转到系统相册选择图片并返回Intent intent new Intent(Intent.ACTION_GET_CONTENT);// 设置图片类型为图片类型intent.setType("image/*&quo…...

对比迁移项目的改动

文章目录 对比迁移项目的改动场景背景解决方案 对比迁移项目的改动 场景背景 同源定制化项目&#xff0c;同一套代码扩展出来的项目&#xff08;从领导口中得知&#xff09; A项目的有三维地图展示&#xff0c;项目B跑起来却加载不出来&#xff0c;但是本地运行A项目代码&…...

数据结构-复杂度

复杂度 1.数据结构1.1算法 2.算法效率2.1复杂度的概念 3.时间复杂度3.1大O渐进表示法3.2时间复杂度计算示例3.2.1 示例13.2.2 示例23.2.3 示例33.2.4 示例43.2.5 示例5&#xff1a;3.2.6 示例63.2.7 示例7 4.空间复杂度4.1.1 示例14.1.2 示例2 5.常见复杂度对比6.复杂度算法题6…...

无人机之放电速率篇

无人机的放电速率是指电池在一定时间内放出其储存电能的能力&#xff0c;这一参数对无人机的飞行时间、性能以及安全性都有重要影响。 一、放电速率的表示方法 放电速率通常用C数来表示。C数越大&#xff0c;表示放电速率越快。例如&#xff0c;一个2C的电池可以在1/2小时内放…...

免费开源AI助手,颠覆你的数字生活体验

Apt Full作为一款开源且完全免费的软件&#xff0c;除了强大的自然语言处理能力&#xff0c;Apt Full还能够对图像和视频进行一系列复杂的AI增强处理&#xff0c;只需简单几步即可实现专业级的效果。 在图像处理方面&#xff0c;Apt Full提供了一套全面的AI工具&#xff0c;包…...

VMware虚拟机三种网络模式详解

主要内容 1. 桥接模式2. NAT模式VMware Network Adapter VMnet8虚拟网卡的作用 3. 仅主机模式VMware Network Adapter VMnet1虚拟网卡的作用设置虚拟机联通外网 4. 总结 参考资料&#xff1a; 1.Vmware虚拟机三种网络模式详解 VMware虚拟机三种网络模式详解之Bridged&#xff0…...

【算法篇】动态规划类(4)——子序列(笔记)

目录 一、Leetcode 题目 1. 最长递增子序列 2. 最长连续递增序列 3. 最长重复子数组 4. 最长公共子序列 5. 不相交的线 6. 最大子序和 7. 判断子序列 8. 不同的子序列 9. 两个字符串的删除操作 10. 编辑距离 11. 回文子串 12. 最长回文子序列 二、动态规划总结 …...

【图解版】力扣第162题:寻找峰值

注意 题目只要求找到一个峰值就可以了。nums[-1]和nums[n]这两个位置是负无穷&#xff0c;也就是说&#xff0c;除了数组的位置之外&#xff0c;其它地方都是负无穷。对于所有有效的 i 都有 nums[i] ! nums[i 1] 方法一 遍历整个数组&#xff0c;找到最高的那个点。时间复杂…...

Windows电脑桌面如何弄个好用的提醒备忘录?

在这个充满挑战的时代&#xff0c;每个人都渴望成为更好的自己。然而&#xff0c;随着生活节奏的加快&#xff0c;我们时常发现自己陷入了各种琐事之中&#xff0c;难以脱身。为了不让重要的事情被遗漏&#xff0c;一款好的提醒备忘录工具就显得尤为关键。那么&#xff0c;Wind…...

Windows API 一 ----起步

目录 1.介绍主函数入口参数。 2. 简单介绍 Windows.h 这个头文件 小结&#xff0c;也聊一聊 1.介绍主函数入口参数。 第一个参数: HINSTANCE 类型的 参数&#xff0c; 称为“实例句柄“&#xff0c;这个参数唯一标志了我们写的这个程序。 第二个参数&#xff1a; HINSTANCE…...

音视频入门基础:H.264专题(19)——FFmpeg源码中,获取avcC封装的H.264码流中每个NALU的长度的实现

一、引言 从《音视频入门基础&#xff1a;H.264专题&#xff08;18&#xff09;——AVCDecoderConfigurationRecord简介》中可以知道&#xff0c;avcC跟AnnexB不一样&#xff0c;avcC包装的H.264码流中&#xff0c;每个NALU前面没有起始码。avcC通过在每个NALU前加上NALUnitL…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...

C# winform教程(二)----checkbox

一、作用 提供一个用户选择或者不选的状态&#xff0c;这是一个可以多选的控件。 二、属性 其实功能大差不差&#xff0c;除了特殊的几个外&#xff0c;与button基本相同&#xff0c;所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...

【Java】Ajax 技术详解

文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...

python可视化:俄乌战争时间线关键节点与深层原因

俄乌战争时间线可视化分析&#xff1a;关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一&#xff0c;自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具&#xff0c;系统分析这场战争的时间线、关键节点及其背后的深层原因&#xff0c;全面…...

AT模式下的全局锁冲突如何解决?

一、全局锁冲突解决方案 1. 业务层重试机制&#xff08;推荐方案&#xff09; Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减&#xff08;自动加全…...