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>
  )
}