一般网站建设多少钱便宜的网站好吗,曲周企业做网站推广,如何自己做一个app软件,普集网站制作原文链接 CSDN 的排版/样式可能有问题#xff0c;去我的博客查看原文系列吧#xff0c;觉得有用的话#xff0c;给我的库点个star#xff0c;关注一下吧 上一篇【Next.js 项目实战系列】06-身份验证
分配 Issue 给用户
本节代码链接
Select Button
# /app/issues/[i…原文链接 CSDN 的排版/样式可能有问题去我的博客查看原文系列吧觉得有用的话给我的库点个star关注一下吧 上一篇【Next.js 项目实战系列】06-身份验证
分配 Issue 给用户
本节代码链接
Select Button
# /app/issues/[id]/AssigneeSelect.tsxuse client;
import { Select } from radix-ui/themes;const AssigneeSelect () {return (Select.RootSelect.Trigger placeholderAssign... /Select.ContentSelect.GroupSelect.LabelSuggestions/Select.LabelSelect.Item value1Castamere/Select.Item/Select.Group/Select.Content/Select.Root);
};
export default AssigneeSelect;效果如下 获取所有用户
本节代码链接
构建 API
# /app/api/users.tsximport { NextRequest, NextResponse } from next/server;
import prisma from /prisma/client;export async function GET(reques: NextRequest) {const users await prisma.user.findMany({ orderBy: { name: asc } });return NextResponse.json(users);
}客户端获取数据
# /app/issues/[id]/AssigneeSelect.tsxuse client;
import { User } from prisma/client;
import { Select } from radix-ui/themes;
import axios from axios;
import { useEffect, useState } from react;const AssigneeSelect () {const [users, setUsers] useStateUser[]([]);useEffect(() {const getUsers async () {const { data } await axios.getUser[](/api/users);setUsers(data);};getUsers();}, []);return (Select.RootSelect.Trigger placeholderAssign... /Select.ContentSelect.GroupSelect.LabelSuggestions/Select.Label{users.map((user) (Select.Item value{user.id} key{user.id}{user.name}/Select.Item))}/Select.Group/Select.Content/Select.Root);
};
export default AssigneeSelect;React-Query
配置 React-Query
本节代码链接
使用如下命令安装 React-Query
npm i tanstack/react-query安装好后在 /app 目录下创建 QueryClientProvider.tsx
# /app/QueryClientProvider.tsxuse client;
import {QueryClient,QueryClientProvider as ReactQueryClientProvider,
} from tanstack/react-query;
import { PropsWithChildren } from react;const queryClient new QueryClient();const QueryClientProvider ({ children }: PropsWithChildren) {return (ReactQueryClientProvider client{queryClient}{children}/ReactQueryClientProvider);
};
export default QueryClientProvider;然后在 layout 中将 body 内所有内容用 QueryClientProvider 包起来
# /app/layout.tsxexport default function RootLayout({children,
}: Readonly{children: React.ReactNode;
}) {return (html langenbody className{inter.className}QueryClientProviderAuthProviderTheme appearancelight accentColorvioletNavBar /main classNamep-5Container{children}/Container/main/Theme/AuthProvider/QueryClientProvider/body/html);
}使用 React-Query
本节代码链接
首先在 /app/issues/[id]/Assign 中去掉之前的 useEffect 和 useState之后参照下面修改
# /app/issues/[id]/AssigneeSelect.tsx...import { useQuery } from tanstack/react-query;import { Skeleton } from /app/components;const AssigneeSelect () {const {data: users,error,isLoading,} useQueryUser[]({// 用于缓存的 key在不同地方调用 useQuery 若 key 一样则不会重复获取queryKey: [users],// 用于获取数据的函数queryFn: () axios.getUser[](/api/users).then((res) res.data),// 数据缓存多久staleTime: 60 * 1000,// 最多重复获取几次retry: 3,});if (error) return null;if (isLoading) return Skeleton /;...};export default AssigneeSelect;完整代码(非 git diff 版)
# /app/issues/[id]/AssigneeSelect.tsxuse client;
import { User } from prisma/client;
import { Select } from radix-ui/themes;
import { useQuery } from tanstack/react-query;
import axios from axios;
import { Skeleton } from /app/components;const AssigneeSelect () {const {data: users,error,isLoading,} useQueryUser[]({queryKey: [users], // 用于缓存的 key在不同地方调用 useQuery 若 key 一样则不会重复获取queryFn: () axios.getUser[](/api/users).then((res) res.data), // 用于获取数据的函数staleTime: 60 * 1000, // 数据缓存多久retry: 3, // 最多重复获取几次});if (error) return null;if (isLoading) return Skeleton /;return (Select.RootSelect.Trigger placeholderAssign... /Select.ContentSelect.GroupSelect.LabelSuggestions/Select.Label{users?.map((user) (Select.Item value{user.id} key{user.id}{user.name}/Select.Item))}/Select.Group/Select.Content/Select.Root);
};
export default AssigneeSelect;
Prisma Relation
本节代码链接
我们需要在 Prisma 中的 Issue model 和 User model 创建一个 Relation
# schema.prismamodel Issue {id Int id default(autoincrement())title String db.VarChar(255)description String db.Textstatus Status default(OPEN)createdAt DateTime default(now())updatedAt DateTime updatedAt()assignedToUserId String? db.VarChar(255)assignedToUser User? relation(fields: [assignedToUserId], references: [id])}model User {id String id default(cuid())name String?email String? uniqueemailVerified DateTime?image String?accounts Account[]sessions Session[]assignedIssues Issue[]}更新修改 Issue API
本节代码链接
首先添加一个新的 zod schema其中 title, description, assignedToUserId 都设置为了 optional
# validationSchema.tsimport { z } from zod;export const issueSchema z.object({title: z.string().min(1, Title is required!).max(255),description: z.string().min(1, Description is required!).max(65535),
});export const patchIssueSchema z.object({title: z.string().min(1, Title is required!).max(255).optional(),description: z.string().min(1, Description is required!).optional(),assignedToUserId: z.string().min(1, AssignedToUserId is required.).max(255).optional().nullable(),
});然后修改 /app/api/issues/[id]/route.tsx
# /app/api/issues/[id]/route.tsx import { patchIssueSchema } from /app/validationSchema;...export async function PATCH(request: NextRequest,{ params }: { params: { id: string } }) {const session await getServerSession(authOptions);if (!session) return NextResponse.json({}, { status: 401 });const body await request.json();// 换成 patchIssueSchemaconst validation patchIssueSchema.safeParse(body);if (!validation.success)return NextResponse.json(validation.error.format(), { status: 400 });// 直接将 title, description, assignedToUserId 结构出来const { title, description, assignedToUserId } body;// 若 body 中有 assignedToUserId则判断该用户是否存在if (assignedToUserId) {const user await prisma.user.findUnique({where: { id: assignedToUserId },});if (!user)return NextResponse.json({ error: Invalid user }, { 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,description,assignedToUserId,},});return NextResponse.json(updatedIssue, { status: 200 });}分配 Issue
本节代码链接
# /app/issues/[id]/AssigneeSelect.tsx...const AssigneeSelect ({ issue }: { issue: Issue }) {...return (Select.Root// 设置初始显示值defaultValue{issue.assignedToUserId || }// 当选择时使用patch (不需要await)onValueChange{(userId) {axios.patch(/api/issues/ issue.id, {assignedToUserId: userId Unassign ? null : userId,});}}Select.Trigger placeholderAssign... /Select.ContentSelect.GroupSelect.LabelSuggestions/Select.Label{/* 添加一个 unassign */}Select.Item valueUnassignUnassign/Select.Item{users?.map((user) (Select.Item value{user.id} key{user.id}{user.name}/Select.Item))}/Select.Group/Select.Content/Select.Root);};export default AssigneeSelect;显示 Toast
本节代码链接
使用如下命令安装
npm i react-hot-toast我们只需要在该组件任意地方添加 Toaster / 组件然后在需要报错的地方调用 toast() 函数即可
# /app/issues/[id]/AssigneeSelect.tsx import toast, { Toaster } from react-hot-toast;const AssigneeSelect ({ issue }: { issue: Issue }) {return (Select.RootdefaultValue{issue.assignedToUserId || }onValueChange{ (userId) {axios.patch(/api/issues/ issue.id, {assignedToUserId: userId Unassign ? null : userId,})// 调用 toast.error()即可.catch(() toast.error(Changes could not be saved!));}}.../Select.RootToaster //);};export default AssigneeSelect;效果如下 CSDN 的排版/样式可能有问题去我的博客查看原文系列吧觉得有用的话给我的库点个star关注一下吧 下一篇讲数据处理
下一篇【Next.js 项目实战系列】08-数据处理