本文实现用户问题分配。
构建分配问题的用户选择组件
查看对照Radix UI 官方网站的Select组件的示例,创建 AssigneeSelect.tsx,位于 /app/issues/[id]目录下。
"use client";
import React from "react";
import { Select } from "@radix-ui/themes";
const AssigneeSelect = () => {
return (
<Select.Root>
<Select.Trigger placeholder="Assign..."></Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Label>Suggestions</Select.Label>
<Select.Item value="1">Kelemi</Select.Item>
</Select.Group>
</Select.Content>
</Select.Root>
);
};
export default AssigneeSelect;
接着,在详细页面中调用 AssigneeSelect组件。

查看网页。

提交Git,命名:Build the assignee select component.
填充用户选择组件
我们从数据库获取用户列表并填充用户选择组件。先创建API, /app/api/新建users目录,再创建route.tsx文件。
import prisma from "@/prisma/client";
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const users = await prisma.user.findMany();
return NextResponse.json(users);
}
然后在AssigneeSelect中调用该API获取用户列表并填充选择组件。我们使用useEffect调用后端数据库,然后用users.map填充选择组件。之前《React入门》系列里有过介绍。

查看网页,选择组件已由数据表里的用户来填充了。
提交Git,命名:Polulate the asignee select component.
设置React Query
React Query的好处在《React中级教程》已详细介绍过,我们用React Query来代替useEffect. 先设置。
安装:npm i @tanstack/react-query@4.35.3
在app目录新建QueryClientProvider.tsx文件。需要改成客户端组件(“use client”;)
"use client";
import {
QueryClient,
QueryClientProvider as ReactQueryClientProvider,
} from "@tanstack/react-query";
import { PropsWithChildren } from "react";
const QueryClientProvider = ({ children }: PropsWithChildren) => {
const queryClient = new QueryClient();
return (
<ReactQueryClientProvider client={queryClient}>
{children}
</ReactQueryClientProvider>
);
};
export default QueryClientProvider;
lauout.tsx调用QueryClientProvider。

提交Git,命名:Set up React Query.
使用 React Query获取数据
去掉useEffect和useState,用ReactQuery代替。下面代码是ReactQuery的常规用法, 加颜色的各行是修改部分。

提交Git,命名:Fetch data with React Query.
将分配的问题添加到Prisma
在schema.prisma里给Issue模型添加User的关联字段assignedToUserId,并设置关联。

再进行迁移:npx prisma migrate dev
检查数据表Issue已增加相应字段。
提交Git,命名:Add assigned issues to prisma schema.
实现API
增强 /api/issues/[id]的PATCH实现,来允许更新Issue的assignedToUserId。之前的IssueSchema是验证title和description的,我们再新建一个schema,允许更新单个或某几个属性。
新建PatchIssueSchema,验证3个属性title,description和 assignedToUserId,都是可选属性【optional()】,assignedToUserId还允许设置为null【nullable()】。
// app/validationSchemas.ts
......
export const patchIssueSchema = z.object({
title: z.string().min(1, "Title is required.").max(255).optional(),
description: z.string().min(1, "Description is required.").max(65535).optional(),
assignedToUserId: z.string().min(1, "assignedToUserId is required.").max(255).optional().nullable(),
});
修改 API。

提交Git,命名:Enhance the API to assign issues.
将问题分配给用户
修改AssigneeSelect.tsx,给Select组件的onValueChange添加处理,通API更新assignedToUserId,另外添加Select一个Item,允许设置回null。

上面代码,AssigneeSelect组件需要传入issue对象,需要在IssueDetailPage里传过去。

提交Git,命名:Assign an issue to a user.
显示 Toast 通知
安装:npm i react-hot-toast@2.4.1
再在AssigneeSelect.tsx中使taost。

我们故意写错 api端点,查看页面。

提交Git,命名:Show toast notifications.
重构AssigneeSelect组件
重构AssigneeSelect组件,onValueChange内联逻辑稍有点长,提取成assignIssue放在渲染组件的外部。另外,useQuery也提取成自定义Hook ,useUsers放在文件最后,这样更清晰。
注意,我们没把重构的函数放在另外文件,只放在同一文件里,这要看实际情况,目录我们的函数是没有必须另起文件的。

提交Git,命名:Refactor AssigneeSelect component.
小结
本文实现了将问题分配给用户的功能。
下一篇实现筛选、排序、分页等功能。