Next.js项目实践(四)– 问题更新

本文根据项目路线实现问题更新功能。


添加编辑按钮

在IssueDetailPage右侧添加编辑按钮,将页面分成两列。对于手机则仅显示单列。

使用Grid组件,响应式显示,初始1列,当屏幕宽度至md时,就显示2列。另外,我们添加的按钮放置一个图标,需要安装radix ui的图标库。

npm i @radix-ui/react-icons

页面显示。

提交Git,命名:Add the edit button.


应用单一责任原则

软件工程有个单一责任原则(Single Responsibility Principle)布局,意思每个模块只专注于一个事情。查看IssueDetailPage,它关注了布局,同时也实现了每个布局块的细节,我们应该将每个布局块的细节移到其他地方。

我们新建问题详细查看组件IssueDetails(左侧)和按钮组件EditIssueButton(右侧),并将页面的相关实现细节移到这两个组件,而页面本身只关注布局。

现在,我们IssueDetailPage就很清晰了。

提交Git,命名:Refactor:Apply the SRP.


构建编辑问题页面

编辑页面与新建页面是一样的,我们将NewIssuePage的内容全部剪切出来形成IssueForm。该组件放在哪里呢?根目录的components不合适,因为IssueForm只用于Issue, 我们在issues目录下新建_components目录,再新建IssueForm.tsx,然后NewIssuePage调用它。注意创建的_components目录是以下划线开头,这样就在路由系统之外,即便添加page.tsx也是无效路径。

在 /issues/[id]下新建edit目录,再新建page.tsx。编辑页面与新建不同的是,它通过id 参数获取 数据库信息,并填充表单。

提交Git,命名:Build the edit issue page.


构建 API

api/issues/ 下新建目录 [id],创建文件route.tsx,创建PATCH函数。验证请求体数据时用zod,将之前的createIssueSchema改成issueSchema. 其它都是常规做法。

// api/issues/[id]/route.tsx
​
import { issueSchema } from "@/app/validationSchems";
import prisma from "@/prisma/client";
import { NextRequest, NextResponse } from "next/server";
​
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: parseInt(params.id) },
    data: {
      title: body.title,
      description: body.description,
    },
  });
  return NextResponse.json(updatedIssue);
}
​

提交Git,命名:Build an API for updating issues.


更新问题

建好了更新API,下一步就来修改IssueForm,使之可以实现更新。

在Form的handleSubmit,判断 issue是否存在,存在就是更新,不存在就是新建,并修改提交按钮的显示。

提交Git,命名:Update issues.


了解缓存

新建一条问题提交返回问题列表时,我们发现刚建的问题并未在列表中,这就涉及到Next.js的缓存了!

有三个层次的缓存:

  1. 数据缓存。当使用fetch()时会有数据缓存,可以自定义缓存的方式。我们这里没用fetch(), 而是用axios,所以没有数据缓存。

2.全路由缓存或者叫”服务器上的缓存”,用于存储静态渲染的输出。前一系列我们说过有动态渲染和静态渲染,静态渲染发生在构建时,而动态渲染则发生在每次请求时。

默认情况,Next.js将带参数的路径如 /issues/1 使用动态渲染,而不带参数的路径 /issues 使用静态渲染。实际看一下:npm run build。能看到 /issues是静态的,而 /issues/[id]则是动态的。

可以手动修改这个特性。搜索”nextjs route sengment config” ,找到网页查看说明。

https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config

修改 issues 页面,添加常数dynamic:

export const dynamic = ‘force-dynamic’;

重新进行构建:npm run build. 就能看到 /issues 已变成动态渲染了。目前我们进行添加一条问题返回列表时,还是看不到新建的问题的,这是由于还有一层缓存叫客户端缓存在起作用,下面就会讲到。

前面的dynamic也可用revalidate代替,其中参数0表示每隔0秒进行刷新,这跟之前用dynamic的效果是一样的,当然我们也可以提高数字,比如60,表示每60秒就刷新。

export const revalidate = 0

3. 路径缓存或叫“客户端缓存”,它存在于客户端浏览器的内存中。Next.js自动缓存页面的有效负载,用户返回某个页面时,自动从缓存取出而不必从后端获取。客户端缓存只持续一个session时期,所以当用户刷新页面时,就会从后端取数据。

当页面是静态渲染时,缓存时间是5分钟;页面是动态渲染时,缓存时间是30秒。可以使用router.refresh()手动刷新。

提交Git,命名:Fix caching issues.


改善加载体验

在NewIssuePage, title输入框与description的markdown编辑不是同时加载的,原因是markdown需要延迟加载,而title框不是。这种体验比较怪异,我们需要将它们调整成同时延迟加载。

先去掉IssueForm的Markdown延迟加载代码.

在 NewIssuePage添加延迟代码。

注意,我们在NewIssuePage里添加了loading属性,用于加载IssueFormSkeleton。这个组件是复制于 loading.tsx的。

而原来的loading改成导入IssueFormSkeleton。

EditIssuePage同样修改成整体延迟加载。

在网页测试刷新新建问题页面及编辑问题页,加载同步已明显改善。

提交Git,命名:Improving the loading experience.


小结

本文实现了问题编辑更新功能。

下一篇实现问题的删除功能。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注