Next.js
CRUD Operations
Implementing Create, Read, Update, and Delete operations using Next.js Server Actions and Prisma.
Server Actions: Functions for Create, Update, Delete.
app/actions/postActions.ts
TS
'use server'
import { revalidatePath } from 'next/cache'
import prisma from '@/lib/prisma'
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
if (!title) return { error: 'Title is required' }
await prisma.post.create({
data: { title, content, published: true }
})
revalidatePath('/posts') // Re-fetch the posts page data
}
export async function deletePost(id: number) {
await prisma.post.delete({
where: { id }
})
revalidatePath('/posts')
}
Create & Read UI: Server component to display items and Client component form to create them.
app/posts/page.tsx
TSX
import prisma from '@/lib/prisma'
import CreatePostForm from '@/components/CreatePostForm'
import DeletePostButton from '@/components/DeletePostButton'
export default async function PostsPage() {
const posts = await prisma.post.findMany({
orderBy: { createdAt: 'desc' }
})
return (
<main className="p-8">
<h1 className="text-2xl font-bold mb-4">Manage Posts</h1>
<CreatePostForm />
<div className="mt-8 space-y-4">
{posts.map((post) => (
<div key={post.id} className="p-4 border rounded shadow-sm flex justify-between">
<div>
<h2 className="text-xl font-semibold">{post.title}</h2>
<p>{post.content}</p>
</div>
<DeletePostButton id={post.id} />
</div>
))}
</div>
</main>
)
}
Create Form Component: Client component invoking a Server Action to create an item.
components/CreatePostForm.tsx
TSX
'use client'
import { createPost } from '@/app/actions/postActions'
import { useRef } from 'react'
export default function CreatePostForm() {
const ref = useRef<HTMLFormElement>(null)
return (
<form
ref={ref}
action={async (formData) => {
await createPost(formData)
ref.current?.reset()
}}
className="space-y-4 max-w-md"
>
<div>
<input
type="text"
name="title"
placeholder="Post Title"
required
className="w-full border p-2 rounded"
/>
</div>
<div>
<textarea
name="content"
placeholder="Post Content"
className="w-full border p-2 rounded"
/>
</div>
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
Create Post
</button>
</form>
)
}
Delete Button Component: Client component invoking a Server Action to delete an item.
components/DeletePostButton.tsx
TSX
'use client'
import { deletePost } from '@/app/actions/postActions'
import { useTransition } from 'react'
export default function DeletePostButton({ id }: { id: number }) {
const [isPending, startTransition] = useTransition()
return (
<button
onClick={() => startTransition(() => deletePost(id))}
disabled={isPending}
className="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 disabled:opacity-50"
>
{isPending ? 'Deleting...' : 'Delete'}
</button>
)
}