Fungsi Server Actions di Next.js 14 menandakan evolusi yang signifikan dalam pendekatan pengolahan data di sisi server. Fungsi ini memungkinkan pengembang untuk mendefinisikan fungsi asinkron langsung di dalam komponen server, guna menangani operasi seperti pengiriman formulir dan perubahan data, tanpa perlu membuat rute API yang terpisah. Pendekatan ini sangat mempermudah aliran data, meningkatkan efisiensi pengembangan, dan juga meningkatkan keamanan aplikasi.
Apa itu Server Actions?
Server Actions merupakan jenis fungsi yang dieksekusi di sisi server dalam Next.js. Fungsi-fungsi ini dapat didefinisikan langsung di dalam komponen React dan diaktifkan melalui formulir atau peristiwa (event). Keunggulan utamanya adalah logika eksekusi sepenuhnya berlangsung di sisi server, sehingga sisi klien hanya bertanggung jawab untuk mengirim permintaan dan menerima respons. Dengan demikian, risiko sensitif logika atau kunci akses terbuka kepada sisi klien dapat dihindari secara alami.
Dengan menambahkan kode di bagian atas berkas komponen… ‘server-only’ Digunakan di dalam instruksi atau fungsi. ‘use server’ Instruksi tersebut memungkinkan fungsi-fungsi ditandai secara eksplisit sebagai operasi yang dilakukan di sisi server. Hal ini memungkinkan para pengembang untuk menulis logika server dengan mudah dalam komponen-komponen aplikasi, misalnya melakukan interaksi yang aman langsung dengan basis data.
Struktur Server Action yang tipikal adalah sebagai berikut: ia dijalankan langsung dalam konteks server, dan memiliki akses ke semua sumber daya (resource) yang tersedia di sisi server.
// app/actions/todo.ts
‘use server‘;
import { revalidatePath } from ‘next/cache‘;
import { db } from ‘@/lib/database‘;
export async function createTodo(formData: FormData) {
const title = formData.get(‘title‘) as string;
// 在服务器端安全地执行数据库操作
await db.todo.create({ data: { title, completed: false } });
// 操作成功后,使特定路径的缓存失效以更新数据
revalidatePath(‘/dashboard‘);
} (Design Philosophy and Working Principles)
Filosofi desain dari Server Actions adalah “membawa logika server kembali ke komponen-komponen”. Dalam aplikasi Next.js tradisional, perubahan data biasanya memerlukan definisi awal dari sebuah objek atau fungsi yang terletak di bagian server. pages/api/ Rute API yang terdapat dalam direktori tersebut kemudian dapat digunakan di komponen klien. fetch Mengirimkan permintaan (request). Pemisahan ini meningkatkan kompleksitas arsitektur.
Server Actions diperkenalkan melalui… ‘use server’ Perintah tersebut bertujuan untuk menandai fungsi-fungsi tersebut sebagai fungsi yang hanya dapat dieksekusi di sisi server saat proses kompilasi. Ketika klien memanggil fungsi-fungsi tersebut, Next.js akan memproses permintaan tersebut melalui sebuah endpoint RPC (Remote Procedure Call) yang aman dan dihasilkan secara otomatis. Next.js akan mengirimkan parameter yang telah diserialisasi ke server, menjalankan fungsi tersebut, lalu mengembalikan hasilnya dalam bentuk yang telah diserialisasi ke klien. Seluruh proses ini bersifat transparan bagi pengembang, sehingga terasa seolah-olah mereka sedang memanggil fungsi lokal saja.
Bagaimana cara mendefinisikan dan menggunakan Server Actions?
Ada dua cara utama untuk mendefinisikan dan menggunakan Server Actions: definisi inline (langsung dalam kode) dan definisi modular. Masing-masing cara cocok untuk skenario yang berbeda, namun keduanya memerlukan penggunaan fitur tertentu dalam sistem. ‘use server’ Instruksi diperlukan untuk menjelaskan lingkungan eksekusi (environment) di mana instruksi tersebut akan dijalankan.
Cara definisi yang dilakukan secara in-line
Anda dapat melakukannya di dalam komponen server, langsung di bagian atas tubuh fungsi (function body). ‘use server’ Instruksi untuk membuat Server Action yang bersifat “inline” (terintegrasi langsung ke dalam kode program). Metode ini cocok digunakan untuk operasi yang sifatnya sederhana dan tidak memiliki tingkat penggunaan yang tinggi (tidak sering digunakan kembali), serta membantu menjaga konsentrasi kode yang terkait.
// app/page.tsx (一个服务器组件)
export default function ServerPage() {
async function handleLogin(formData: FormData) {
‘use server‘;
const email = formData.get(‘email‘);
const password = formData.get(‘password‘);
// 在此处进行身份验证逻辑
// ...
}
return (
<form action={handleLogin}>
<input type="email" name="email" />
<input type="password" name="password" />
<button type="submit">登录</button>
</form>
);
} Perlu diperhatikan bahwa, untuk mendapatkan tingkat keamanan tipe (type safety) dan optimisasi yang terbaik (seperti proses “Tree-shaking”), pihak Next.js secara resmi lebih merekomendasikan penggunaan pendekatan definisi berbasis modul (modular definition).
Cara mendefinisikan secara modular
Untuk logika yang lebih kompleks atau yang perlu digunakan berulang kali di berbagai tempat, disarankan untuk mendefinisikan Server Actions dalam file modul yang terpisah. app/actions/ Berada di dalam direktori. Hal ini membantu menjaga kode tetap termodulasi dan mudah diperawat, serta memudahkan proses pengujian unit (unit testing).
Pertama-tama, definisikan dan ekspor aksi (action) Anda ke dalam sebuah file yang terpisah:
// app/actions/user.ts
‘use server‘;
import { z } from ‘zod‘;
import { db } from ‘@/lib/db‘;
import { revalidateTag } from ‘next/cache‘;
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
export async function createUser(prevState: any, formData: FormData) {
const validatedFields = UserSchema.safeParse({
name: formData.get(‘name‘),
email: formData.get(‘email‘),
});
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
};
}
await db.user.create({ data: validatedFields.data });
revalidateTag(‘user-list‘); // 使用标签重新验证缓存
return { message: ‘用户创建成功!‘ };
} Kemudian, impor dan gunakan komponen tersebut di dalam komponen klien atau server. Di dalam komponen klien, komponen tersebut perlu dikombinasikan dengan React. useActionState Gunakan Hook untuk mengelola status.
// app/components/CreateUserForm.tsx
‘use client‘;
import { createUser } from ‘@/app/actions/user‘;
import { useActionState } from ‘react‘;
export function CreateUserForm() {
const [state, formAction, isPending] = useActionState(createUser, null);
return (
<form action="/id/formAction/" data-trp-original-action="{formAction}">
<div>
<label htmlfor="name">Nama.</label>
<input id="name" name="name" />
{state?.errors?.name && <span>{state.errors.name}</span>}
</div>
<div>
<label htmlfor="email">\nSurel</label>
<input id="email" name="email" type="email" />
{state?.errors?.email && <span>{state.errors.email}</span>}
</div>
<button type="submit" disabled="{isPending}">
{isPending ? ‘Sedang dibuat…‘ : ‘Membuat pengguna‘}
</button>
{state?.message && <p>{state.message}</p>}
<input type="hidden" name="trp-form-language" value="id"/></form>
);
} Keunggulan Utama dan Penerapan dari Server Actions
Pengenalan fitur Server Actions telah menyelesaikan berbagai masalah kritis dalam pengembangan aplikasi berbasis teknologi full-stack, baik dari segi keamanan maupun pengalaman pengembangan. Kualitas aplikasi tersebut telah meningkat secara signifikan.
Data flow yang disederhanakan dan keamanan tipe dari ujung ke ujung (end-to-end type safety)
Pendekatan tradisional menggunakan “API routing” + fetch”Mode” ini memiliki fitur untuk mengganti konteks (context switching) dan menetapkan titik pemutusan (type breakpoints). Server Actions memungkinkan Anda menganggap fungsi-fungsi server sebagai modul yang dapat diimpor, dan dengan menggabungkannya dengan TypeScript, Anda dapat mencapai keamanan tipe (type safety) yang komprehensif dari skema basis data (database schema) hingga formulir di sisi pengguna (frontend). Anda dapat mendefinisikan parameter input dalam bentuk Zod atau format skema serupa di dalam fungsi aksi (action functions), sehingga di sisi klien (client) Anda akan mendapatkan petunjuk tipe (type hints) yang akurat serta mekanisme validasi yang efektif, yang secara signifikan mengurangi kemungkinan terjadinya kesalahan saat program dijalankan (runtime errors).
推荐阅读 Mengapa memilih Tailwind CSS: Penjelasan rinci tentang keunggulan inti dan praktik terbaiknya.。
Keamanan yang ditingkatkan dan perlindungan bawaan
Aksi server secara default dilindungi oleh serangkaian mekanisme keamanan. Next.js secara otomatis menerapkan langkah-langkah keamanan tersebut untuk semua aplikasi yang dibangun menggunakan framework ini. POST Implementasi Server Actions pada metode tersebut melindungi dari serangan penipuan permintaan antar situs (Cross-Site Request Forgery/CSRF) dengan melakukan pemeriksaan tertentu. Origin 和 Host Permintaan tersebut diverifikasi berdasarkan sumbernya. Yang lebih penting lagi, karena logika bisnis (seperti kueri database atau pemanggilan layanan pihak ketiga) dijalankan di server, variabel lingkungan yang sensitif dan kunci API tidak akan pernah bocor ke dalam paket yang dikirim ke klien.
Mekanisme pemeriksaan ulang cache yang efisien
Server Actions terintegrasi secara mendalam dengan sistem cache Next.js. Setelah terjadi perubahan data, Anda dapat menggunakan fitur tersebut untuk… revalidatePath 或 revalidateTag Fungsi tersebut digunakan untuk secara spesifik membatalkan (membatalkan efek) data cache yang berada di jalur tertentu atau yang memiliki tag tertentu. Dengan demikian, setelah proses pembuatan artikel blog selesai, Anda dapat langsung memperbarui cache halaman daftar artikel, sehingga pengguna dapat melihat data terbaru tanpa perlu menunggu siklus pembangunan kembali konten statis secara bertahap (Incremental Static ReGeneration/ISR).
‘use server‘;
import { revalidatePath, revalidateTag } from ‘next/cache‘;
export async function updatePost(id: string, content: string) {
await db.post.update({ where: { id }, data: { content } });
// 方式一:重新验证特定路径
revalidatePath(`/posts/${id}`);
// 方式二:重新验证所有带有该标签的缓存数据
revalidateTag(‘posts‘);
} (Progressive Enhancement and User Experience Optimization)
Bahkan jika pengunduhan JavaScript di sisi klien gagal atau sepenuhnya dinonaktifkan, penggunaan tetap dapat dilanjutkan. action Formulir HTML yang memiliki atribut yang mengarah ke Server Action masih dapat berfungsi dengan normal, yang memenuhi persyaratan dasar dari peningkatan berkelanjutan (progressive enhancement). Untuk browser modern, Anda dapat memanfaatkan fitur ini. useFormStatus、useOptimistic Gunakan React Hook untuk menyediakan pengalaman pengguna yang lebih baik, misalnya dengan menampilkan status pengunduhan saat menunggu respons dari server, atau melakukan pembaruan data secara proaktif (optimistic updates).
‘use client‘;
import { experimental_useOptimistic as useOptimistic } from ‘react‘;
import { sendMessage } from ‘./actions‘;
function Thread({ messages }) {
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, { text: newMessage, sending: true }]
);
async function formAction(formData) {
const message = formData.get(‘message‘);
addOptimisticMessage(message); // 立即乐观更新UI
await sendMessage(message); // 调用 Server Action
}
return (
<>
{optimisticMessages.map((msg, idx) => (
<div key="{idx}">{msg.text} {msg.sending && ‘(Sedang dikirim…)‘}</div>
))}
<form action="/id/formAction/" data-trp-original-action="{formAction}">...<input type="hidden" name="trp-form-language" value="id"/></form>
</>
);
} Menyimpulkan.
Server Actions di Next.js 14 merupakan fitur yang revolusioner, karena dengan mengintegrasikan logika server lebih erat dan secara eksplisit ke dalam komponen UI, fitur ini secara signifikan menyederhanakan kompleksitas pengembangan berbasis full-stack. Server Actions bukan hanya merupakan solusi pengganti untuk routing API, tetapi juga mewakili paradigma pengolahan data yang lebih aman, lebih efisien, dan lebih ramah pengguna. Dengan menyediakan aliran data yang lebih sederhana, nilai default keamanan yang kuat, kontrol cache yang detail, serta dukungan terhadap peningkatan aplikasi secara bertahap (progressive enhancement), Server Actions sangat meningkatkan pengalaman dan kualitas dalam pembuatan aplikasi web modern. Memahami dan menerapkan fitur ini dengan baik merupakan kunci untuk membuat aplikasi Next.js generasi berikutnya yang memiliki kinerja tinggi dan mudah diperawat.
FAQ - Pertanyaan yang Sering Diajukan.
Apakah bisa langsung mendefinisikan Server Action di dalam komponen klien (client-side components)?
Tidak boleh.‘use server’ Instruksi tersebut hanya dapat digunakan dalam modul yang berada di lingkungan server. Pada bagian yang ditandai dengan… ‘use client’ Mendefinisikan Server Action langsung dalam file komponen klien dapat menyebabkan kesalahan saat proses pembangunan (build). Cara yang benar adalah dengan mendefinisikan Server Action dalam file modul yang terpisah atau dalam komponen server, kemudian mengimpor dan memanggilnya dari file komponen klien.
Apakah Server Actions hanya terbatas pada pemrosesan data formulir?
Bukan. Meskipun pengiriman formulir merupakan kasus penggunaan yang paling umum dari Server Actions (melalui…) FormData Objek tersebut dapat menerima parameter apa pun yang dapat diserialisasi, termasuk string, angka, nilai boolean, array, dan objek biasa. Anda dapat memanggilnya seperti memanggil fungsi asinkron biasa, dan mengirimkan parameter yang diperlukan.
Bagaimana cara menangani kesalahan yang terjadi saat Server Actions sedang dijalankan?
Anda seharusnya menggunakannya di dalam fungsi Server Action. try...catch Kode tersebut digunakan untuk menangkap dan menangani kesalahan (error handling) pada blok tertentu. Setelah itu, informasi kesalahan dapat dikirimkan kembali ke klien dalam bentuk objek. Di sisi klien, objek tersebut dapat dimanfaatkan untuk mengambil tindakan yang sesuai. useActionState Gunakan status yang dikembalikan oleh fungsi `Hook` untuk merender pesan kesalahan. Pastikan untuk tidak mengirimkan tumpukan kesalahan server yang sensitif langsung ke klien, melainkan mengirimkan pesan kesalahan yang ramah pengguna.
Apakah penggunaan Server Actions akan mempengaruhi kinerja aplikasi saya?
Jika digunakan dengan benar, Server Actions umumnya dapat membantu meningkatkan persepsi kinerja aplikasi. Server Actions mengurangi ukuran paket JavaScript di sisi klien, karena logika pemrosesan dilakukan di server. Dengan demikian, aplikasi menjadi lebih ringan dan lebih cepat dalam menjalankan fungsinya. revalidatePath 或 revalidateTag Dengan melakukan pemanggilan tersebut, dapat dihindari pengunduhan ulang seluruh halaman yang tidak perlu. Namun, perlu diperhatikan efisiensi eksekusi fungsi aksi (action function) untuk menghindari operasi sinkron yang berlangsung lama dan menghambat proses permintaan (request). Untuk tugas-tugas yang membutuhkan waktu lama, sebaiknya dipertimbangkan penggunaan antrian pemrosesan (async queue). Selain itu, pemanggilan berulang terhadap Server Action yang bersifat sederhana dapat meningkatkan jumlah lalu lintas data di jaringan; dalam hal ini perlu dipertimbangkan apakah penggunaan mekanisme manajemen status di sisi klien (client-side state management) cocok atau tidak.
Selanjutnya, apa yang harus kita lakukan selanjutnya?
Bacaan lanjutan dan pengetahuan praktis.
Konten-konten berikut terkait dengan topik artikel ini dan cocok untuk dibaca lebih lanjut. Lebih baik mulai dengan artikel yang paling dekat dengan pertanyaan Anda saat ini, lalu secara bertahap memperluas ke topik terkait, yang biasanya akan memberikan hasil yang lebih baik.
- Pembangunan Situs Web: Panduan Teknis Lengkap untuk Membangun Situs Web Profesional Dari Nol
- Panduan Proses Pembangunan Situs Web Lengkap: Analisis Langkah-langkah Kompleks Dari Nol Sampai Siap Dioperasikan Secara Profesional
- Menguasai Inti Tailwind CSS: Panduan Pengembangan Frontend Modern Dari Kelas-Kelas Praktis Hingga Desain Responsif
- Menguasai seluruh proses pembangunan situs web: Panduan Teknis dan Praktik Terbaik dari Nol Hingga Situs Siap Diunggah
- Membangun Situs Web yang Sukses: Panduan Lengkap Pembangunan Situs Web dari Nol Sampai Satu