Bahasa Indonesia

Panduan komprehensif untuk Server Actions Next.js 14, mencakup praktik terbaik penanganan formulir, validasi data, pertimbangan keamanan, dan teknik canggih untuk membangun aplikasi web modern.

Server Actions Next.js 14: Menguasai Praktik Terbaik Penanganan Formulir

Next.js 14 memperkenalkan fitur-fitur canggih untuk membangun aplikasi web yang berkinerja tinggi dan ramah pengguna. Di antaranya, Server Actions menonjol sebagai cara transformatif untuk menangani pengiriman formulir dan mutasi data langsung di server. Panduan ini memberikan gambaran komprehensif tentang Server Actions di Next.js 14, dengan fokus pada praktik terbaik untuk penanganan formulir, validasi data, keamanan, dan teknik-teknik canggih. Kami akan menjelajahi contoh-contoh praktis dan memberikan wawasan yang dapat ditindaklanjuti untuk membantu Anda membangun aplikasi web yang tangguh dan skalabel.

Apa itu Server Actions Next.js?

Server Actions adalah fungsi asinkron yang berjalan di server dan dapat dipanggil langsung dari komponen React. Mereka menghilangkan kebutuhan akan rute API tradisional untuk menangani pengiriman formulir dan mutasi data, menghasilkan kode yang lebih sederhana, keamanan yang lebih baik, dan performa yang ditingkatkan. Server Actions adalah React Server Components (RSC), yang berarti mereka dieksekusi di server, menghasilkan waktu muat halaman awal yang lebih cepat dan SEO yang lebih baik.

Manfaat Utama Server Actions:

Menyiapkan Proyek Next.js 14 Anda

Sebelum mendalami Server Actions, pastikan Anda telah menyiapkan proyek Next.js 14. Jika Anda memulai dari awal, buat proyek baru menggunakan perintah berikut:

npx create-next-app@latest my-next-app

Pastikan proyek Anda menggunakan struktur direktori app untuk memanfaatkan sepenuhnya Server Components dan Actions.

Penanganan Formulir Dasar dengan Server Actions

Mari kita mulai dengan contoh sederhana: sebuah formulir yang mengirimkan data untuk membuat item baru di database. Kita akan menggunakan formulir sederhana dengan satu kolom input dan tombol kirim.

Contoh: Membuat Item Baru

Pertama, definisikan fungsi Server Action di dalam komponen React Anda. Fungsi ini akan menangani logika pengiriman formulir di server.

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  // Simulasi interaksi database
  console.log('Membuat item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulasi latensi

  console.log('Item berhasil dibuat!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    await createItem(formData);
    setIsSubmitting(false);
  }

  return (
    
); }

Penjelasan:

Validasi Data

Validasi data sangat penting untuk memastikan integritas data dan mencegah kerentanan keamanan. Server Actions memberikan kesempatan yang sangat baik untuk melakukan validasi di sisi server. Pendekatan ini membantu mengurangi risiko yang terkait dengan validasi di sisi klien saja.

Contoh: Memvalidasi Data Input

Modifikasi Server Action createItem untuk menyertakan logika validasi.

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  if (!name || name.length < 3) {
    throw new Error('Nama item harus memiliki panjang minimal 3 karakter.');
  }

  // Simulasi interaksi database
  console.log('Membuat item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulasi latensi

  console.log('Item berhasil dibuat!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'Terjadi kesalahan.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

Penjelasan:

Menggunakan Pustaka Validasi

Untuk skenario validasi yang lebih kompleks, pertimbangkan untuk menggunakan pustaka validasi seperti:

Berikut adalah contoh menggunakan Zod:

// app/utils/validation.ts
import { z } from 'zod';

export const CreateItemSchema = z.object({
  name: z.string().min(3, 'Nama item harus memiliki panjang minimal 3 karakter.'),
});
// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';
import { CreateItemSchema } from '../utils/validation';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  const validatedFields = CreateItemSchema.safeParse({ name });

  if (!validatedFields.success) {
    return { errors: validatedFields.error.flatten().fieldErrors };
  }

  // Simulasi interaksi database
  console.log('Membuat item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulasi latensi

  console.log('Item berhasil dibuat!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'Terjadi kesalahan.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

Penjelasan:

Pertimbangan Keamanan

Server Actions meningkatkan keamanan dengan mengeksekusi kode di server, tetapi tetap penting untuk mengikuti praktik terbaik keamanan untuk melindungi aplikasi Anda dari ancaman umum.

Mencegah Cross-Site Request Forgery (CSRF)

Serangan CSRF mengeksploitasi kepercayaan yang dimiliki sebuah situs web terhadap browser pengguna. Untuk mencegah serangan CSRF, terapkan mekanisme perlindungan CSRF.

Next.js secara otomatis menangani perlindungan CSRF saat menggunakan Server Actions. Kerangka kerja ini menghasilkan dan memvalidasi token CSRF untuk setiap pengiriman formulir, memastikan bahwa permintaan berasal dari aplikasi Anda.

Menangani Otentikasi dan Otorisasi Pengguna

Pastikan hanya pengguna yang berwenang yang dapat melakukan tindakan tertentu. Terapkan mekanisme otentikasi dan otorisasi untuk melindungi data dan fungsionalitas sensitif.

Berikut adalah contoh menggunakan NextAuth.js untuk melindungi Server Action:

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';
import { getServerSession } from 'next-auth';
import { authOptions } from '../../app/api/auth/[...nextauth]/route';

async function createItem(formData: FormData) {
  'use server'

  const session = await getServerSession(authOptions);

  if (!session) {
    throw new Error('Tidak Sah');
  }

  const name = formData.get('name') as string;

  // Simulasi interaksi database
  console.log('Membuat item:', name, 'oleh pengguna:', session.user?.email);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulasi latensi

  console.log('Item berhasil dibuat!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'Terjadi kesalahan.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

Penjelasan:

Membersihkan Data Input

Bersihkan data input untuk mencegah serangan Cross-Site Scripting (XSS). Serangan XSS terjadi ketika kode berbahaya disuntikkan ke dalam situs web, yang berpotensi membahayakan data pengguna atau fungsionalitas aplikasi.

Gunakan pustaka seperti DOMPurify atau sanitize-html untuk membersihkan input yang diberikan pengguna sebelum memprosesnya di Server Actions Anda.

Teknik Tingkat Lanjut

Setelah kita membahas dasar-dasarnya, mari kita jelajahi beberapa teknik canggih untuk menggunakan Server Actions secara efektif.

Pembaruan Optimistis

Pembaruan optimistis memberikan pengalaman pengguna yang lebih baik dengan segera memperbarui UI seolah-olah tindakan akan berhasil, bahkan sebelum server mengonfirmasinya. Jika tindakan gagal di server, UI akan dikembalikan ke keadaan sebelumnya.

// app/components/UpdateItemForm.tsx
'use client';

import { useState } from 'react';

async function updateItem(id: string, formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  // Simulasi interaksi database
  console.log('Memperbarui item:', id, 'dengan nama:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulasi latensi

  // Simulasi kegagalan (untuk tujuan demonstrasi)
  const shouldFail = Math.random() < 0.5;
  if (shouldFail) {
    throw new Error('Gagal memperbarui item.');
  }

  console.log('Item berhasil diperbarui!');
  return { name }; // Kembalikan nama yang diperbarui
}

export default function UpdateItemForm({ id, initialName }: { id: string; initialName: string }) {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  const [itemName, setItemName] = useState(initialName);

  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);

    // Perbarui UI secara optimistis
    const newName = formData.get('name') as string;
    setItemName(newName);

    try {
      const result = await updateItem(id, formData);
      //Jika berhasil maka pembaruan sudah tercermin di UI melalui setItemName

    } catch (error: any) {
      setErrorMessage(error.message || 'Terjadi kesalahan.');
      // Kembalikan UI jika terjadi kesalahan
      setItemName(initialName);
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    

Nama Saat Ini: {itemName}

{errorMessage &&

{errorMessage}

}
); }

Penjelasan:

Merevalidasi Data

Setelah Server Action memodifikasi data, Anda mungkin perlu merevalidasi data yang di-cache untuk memastikan bahwa UI mencerminkan perubahan terbaru. Next.js menyediakan beberapa cara untuk merevalidasi data:

Berikut adalah contoh merevalidasi path setelah membuat item baru:

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';
import { revalidatePath } from 'next/cache';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  // Simulasi interaksi database
  console.log('Membuat item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulasi latensi

  console.log('Item berhasil dibuat!');

  revalidatePath('/items'); // Revalidasi path /items
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'Terjadi kesalahan.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

Penjelasan:

Praktik Terbaik untuk Server Actions

Untuk memaksimalkan manfaat Server Actions, pertimbangkan praktik terbaik berikut:

Kesalahan Umum dan Cara Menghindarinya

Meskipun Server Actions menawarkan banyak keuntungan, ada beberapa kesalahan umum yang perlu diwaspadai:

Kesimpulan

Server Actions Next.js 14 menyediakan cara yang kuat dan efisien untuk menangani pengiriman formulir dan mutasi data langsung di server. Dengan mengikuti praktik terbaik yang diuraikan dalam panduan ini, Anda dapat membangun aplikasi web yang tangguh, aman, dan berkinerja tinggi. Manfaatkan Server Actions untuk menyederhanakan kode Anda, meningkatkan keamanan, dan meningkatkan pengalaman pengguna secara keseluruhan. Saat Anda mengintegrasikan prinsip-prinsip ini, pertimbangkan dampak global dari pilihan pengembangan Anda. Pastikan formulir dan proses penanganan data Anda dapat diakses, aman, dan ramah pengguna untuk audiens internasional yang beragam. Komitmen terhadap inklusivitas ini tidak hanya akan meningkatkan kegunaan aplikasi Anda tetapi juga memperluas jangkauan dan efektivitasnya dalam skala global.