大数据

nextjs使用shadcn ui前后端交互demo

/app/api/comments/route.ts

import {NextResponse} from "next/server";

// 模拟数据
let comments = [
    { id: 1, text: '这是第一条评论', author: '用户A' },
    { id: 2, text: '这是第二条评论', author: '用户B' },
]

export async function GET() {
    return NextResponse.json(comments);
}

export async function POST(request: Request) {
    const {text} = await request.json()

    // 模拟存储
    const newComment = {
        id: comments.length + 1,
        text,
        author: '当前用户',
    }

    comments.push(newComment)

    return NextResponse.json(newComment, {status: 201})
}

/components/ComponentList.tsx

"use client"
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";

interface Comment {
    id: number;
    text: string;
    author: string;
}

export function CommentList({comments}: { comments: Comment[] }) {
    return (
        <Card className="mb-6">
            <CardHeader>
                <CardTitle>评论列表</CardTitle>
            </CardHeader>
            <CardContent>
                <ul className="space-y-4">
                    {comments.map((comment) => (
                        <li key={comment.id} className="border-b pb-4">
                            <p className="font-medium">{comment.author}</p>
                            <p className="text-gray-600">{comment.text}</p>
                        </li>
                    ))}
                </ul>
            </CardContent>
        </Card>
    )
}

/components/ComponentDialog.tsx

"use client"

import React, {useState} from 'react';
import {Button} from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
} from '@/components/ui/dialog';
import {Input} from '@/components/ui/input';
import {Label} from '@/components/ui/label';
import {useRouter} from 'next/navigation';
import {toast} from "sonner"

export function CommentDialog() {
    const [open, setOpen] = useState(false);
    const [comment, setComment] = useState('');
    const router = useRouter();

    const handleSubmit = async (e: React.FormEvent) =>
    {
        e.preventDefault();

        try {
            const response = await fetch("/api/comments", {
                method: "POST",
                headers: {"Content-Type": "application/json"},
                body: JSON.stringify({text: comment}),
            })

            if (!response.ok) {
                throw new Error("提交失败")
            }

            toast("评论提交成功")
            setOpen(false);
            router.refresh()

            setComment('')
        } catch (error) {
            toast("提交评论时出错")
        }
    }

    return (
        <Dialog open={open} onOpenChange={setOpen}>
            <DialogTrigger asChild>
                <Button variant="outline">添加评论</Button>
            </DialogTrigger>
            <DialogContent>
                <DialogHeader>
                    <DialogTitle>添加新评论</DialogTitle>
                </DialogHeader>
                <form onSubmit={handleSubmit} className="space-y-4">
                    <div className="space-y-2">
                        <Label htmlFor="comment">评论内容</Label>
                        <Input
                            id="comment"
                            value={comment}
                            onChange={(e) => setComment(e.target.value)}
                            required
                        />
                    </div>
                    <Button type="submit">提交</Button>
                </form>
            </DialogContent>
        </Dialog>
    )
}

/app/layout.tsx

import "./globals.css";

import { Toaster } from "@/components/ui/sonner"
import React from "react";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className="antialiased"
      >
      <main>
          {children}
      </main>
      <Toaster />
      </body>
    </html>
  );
}

/app/page.tsx

import {CommentList} from "@/components/CommentList";
import {CommentDialog} from "@/components/CommentDialog";

export default async function Home() {
    const response = await fetch("http://localhost:3000/api/comments", {
        method: "GET",
        headers: {"Content-Type": "application/json"}
    });
    const comments = await response.json();
  return (
      <div className="flex min-h-svh w-full items-center justify-center p-6 md:p-10">
          <div className="w-full max-w-sm">
              <h1 className="text-2xl font-bold mb-6">评论系统</h1>

              {/* 服务端获取的评论数据传递给客户端组件 */}
              <CommentList comments={comments} />

              {/* 添加评论的对话框 */}
              <CommentDialog />
          </div>
      </div>
  );
}