TechSolution

Programing tutorial

Penerapan Server Action Pada Nextjs app Router

nextjs server action

Next.js 13+ mengintegrasikan React Actions untuk menyediakan solusi bawaan untuk server mutations. Server Actions memungkinkan Kita untuk mendefinisikan fungsi server yang asinkron dan memanggilnya langsung dari komponen React Kita

Konsep Server Actions

Server Actions adalah fungsi yang berjalan di server-side tetapi dapat dipanggil dari client. Ini meningkatkan kemampuan server-side rendering Next.js menjadi level baru. Dengan beralih ke Server Actions, mereka dapat dipahami sebagai Server Functions, tetapi spesifik yang diaktifkan sebagai tindakan. Integrasi mereka dengan elemen form, terutama melalui prop action, memastikan bahwa form tetap interaktif bahkan sebelum JavaScript client-side dimuat. Ini berarti pengalaman pengguna yang lebih halus, dengan hidrasi React tidak menjadi prasyarat untuk pengiriman form

Berikut adalah contoh sederhana Server Action di Next.js app Router:

import {createUser} from '@/actions/users.ts';
export default function Page() {
 async function create(formData: FormData) {
   'use server';
   const id = await createUser(formData); // memanggil fungsi component server
 }
 return (
   <form action={create}>
     <input type="text" name="name" />
     <input type="text" name="email" />
     <button type="submit">Submit</button>
   </form>
 );
}

Untuk menggunakan Server Actions, Kita dapat menggunakan prop action atau formAction dari React. Prop action memungkinkan Kita memanggil Server Action pada elemen <form>. Sementara itu, prop formAction memungkinkan Kita menangani elemen <button>, <input type=“submit”>, dan <input type=“image”> dalam <form>

Integrasi Server Actions pada Projek

Kita akan membuat sebuah server action untuk insert data menggunakan prisma.

Terlebih dahulu kita membuat config prisma untuk pengolahan database. Untuk instal dan konfigurasi Prisma pada projek kita bisa pergi ke dokumentasi prisma atau tutorial Prisma integration in Nextjs app Router

Buat sebuah file pada app/config/prisma.ts:

//app/config/prisma.ts:
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log: ["query"],
  });
if (process.env.NODE_ENV != "production") globalForPrisma.prisma;

Buat sebuah file server action /app/actions/users.ts untuk menangani actions:

// app/actions/users.ts
"use server";
import { prisma } from "@/app/lib/prisma"; // call config prisma library
import { revalidatePath, revalidateTag } from "next/cache";

async function createUser(formData: FormData) {
  try {
    const name = formData.get("name") as string;
    const email = formData.get("email") as string;
    await prisma.users.create({
      data: {
        name,
        email
      },
    });
    revalidateTag("user"); // mutation data
    return { message: "success" };
  } catch (e) {
    return { message: "Failed created data" };
  }
}

async function deleteUser(id: any) {
  try {
    await prisma.users.delete({
      where: {
        id: parseInt(id),
      },
    });
    return revalidatePath("users");
  } catch (e) {
    return { message: "Failed to deletes" };
  }
}
export {
  createUser,
  deleteUser
};

Kemudian kita bisa memanggil pada komponent:

// app/user/page.tsx
'use client'
import { experimental_useFormState as useFormState } from 'react-dom'
import { useFormStatus } from 'react-dom'
import { createUser } from '@/app/actions/users'
const initialState = {
 message: null,
}
function SubmitButton() {
 const { pending } = useFormStatus()
 return (
   <button type="submit" aria-disabled={pending}>
     Add
   </button>
 )
}
export function AddForm() {
 const [state, formAction] = useFormState(createUser, initialState)
 return (
   <form action={formAction}>
     <label htmlFor="todo">Enter Task</label>
     <input type="text" id="todo" name="todo" required />
     <SubmitButton />
     <p aria-live="polite" className="sr-only" role="status">
       {state?.message}
     </p>
   </form>
 )
}

Atau kita bisa memanggil dari sebuah function

// app/user/page.tsx
'use client'
import { useToast } from "@/components/ui/use-toast";
import { experimental_useFormState as useFormState } from 'react-dom'
import { useFormStatus } from 'react-dom'
import { createUser } from '@/app/actions/users'

function SubmitButton() {
 const { pending } = useFormStatus()
 return (
   <button type="submit" aria-disabled={pending}>
     Add
   </button>
 )
}
export function Page() {
  const { toast } = useToast();
  const router = useRouter();

  const createNewData = async (formData: FormData) => {
    const status = await createUser(formData);
    if (status.message == "success") {
      toast({
        title: "✓ Success",
        description: "New Data created successfully !",
      });
    } else {
      toast({
        title: "⤬ Fail !",
        description: status.message,
      });
    }
  };
 return (
   <form action={createNewData}>
     <label htmlFor="todo">Enter Task</label>
     <input type="text" id="todo" name="todo" required />
     <SubmitButton />
     <p aria-live="polite" className="sr-only" role="status">
       {state?.message}
     </p>
   </form>
 )
}

Dengan Server Actions, Kita dapat menulis logika server yang kompleks dan menjalankannya dengan aman di server, tanpa harus membuat rute API secara manual. Tetapi Jika resource kita digunakan oleh sistem lain, maka seharusnya kita menggunakan dengan metode api handler pada nextjs.

Happy Coding!

By raflesngln@gmail.com

Stay Hungry Stay Foolish

Leave a Reply

Your email address will not be published. Required fields are marked *