در این مقاله قصد داریم تا Server Actionها و نحوه استفاده از آن‌ها را باهم بررسی کنیم. Server Actionها یکی از ویژگی‌های آلفا در Next.js هستند که توسعه‌دهندگان آن‌ها را بر اساس React Actionها ساخته‌اند. Server Actionها روشی قدرتمند برای مدیریت data mutationهای سمت سرور، کاهش استفاده از جاوااسکریپت در سمت کلاینت و پیشرفت تدریجی فرم‌ها ارائه می‌دهند.

نحوه فعال کردن Server Actionها

برای فعال کردن Server Actionها در پروژه Next.js خود، باید ابتدا experimental را فعال کنیم. در فایل next.config.js گزینه serverActions را flag می‌کنیم.

const nextConfig = {
  experimental: {
    serverActions: true,
  },
};

ساخت Server Actionها

Server Actionها با تعریف یک تابع Asynchronous با استفاده از دستور use serverدر قسمت بالای بدنه تابع ساخته می‌شوند. این توابع باید دارای آرگومان‌ها و یک مقدار بازگشتی قابل سریال‌سازی بر اساس پروتکل React Server Components باشند.

async function myNewAction() {
  "use server";
  ...
}

همچنین می‌توانیم از یک دستور سطح بالایuse serverدر قسمت بالای فایل استفاده کنیم. این کار در صورتی که یک فایل واحد داشته باشیم که چندین Server Action را export می‌کند و یا اگر در حال import کردن یک Server Action در یک کامپوننت کلاینت هستیم، می‌تواند بسیار مفید باشد.

"use server";
 
export async function myAction() {
 ...
}

فراخوانی Server Actionها

سه روش برای فراخوانی Server Actionها وجود دارد که در ادامه هر یک آن‌ها را بررسی خواهیم کرد.

action: می‌توانیم از action prop مربوط به React برای فراخوانی یک Server Actionدر المنت <form>استفاده کنیم.

export default function AddToCart({ productId }) {
  async function addItem(data) {
    'use server';
 
    const cartId = cookies().get('cartId')?.value;
    await saveToDb({ cartId, data });
  }
 
  return (
    <form action={addItem}>
      <button type="submit">Add to Cart</button>
    </form>
  );
}

formAction: می‌توانیم برای مدیریت المنت‌هایی مانند <button>، <input type=”submit”>و <input type=”image”>در یک <form>از formAction prop در React استفاده کنیم.

export default function Form() {
  async function handleSubmit() {
    "use server";
    ...
  }
 
  async function submitImage() {
    "use server";
    ...
  }
 
  return (
    <form action={handleSubmit}>
      <input type="text" name="name" />
      <input type="image" formAction={submitImage} />
      <button type="submit">Submit</button>
    </form>
  );
}

فراخوانی سفارشی با startTransition: می‌توانیم Server Actionها را بدون استفاده از action یا formAction فراخوانی کنیم. برای این کار باید از startTransition استفاده کنیم. این روش Progressive Enhancement را غیرفعال می‌کند.

app/_components/client-component.js

'use client';
 
import { useTransition } from 'react';
import { addItem } from '../_actions';
 
function ClientComponent({ id }) {
  let [isPending, startTransition] = useTransition();
 
  return <div onClick={() => startTransition(addItem(id))}>Add To Cart</div>;
}
app/_actions.js

'use server';
 
async function addItem(id) {
  await addItemToDb(id);
  revalidatePath(`/product/${id}`);
}

فراخوانی سفارشی بدون startTransition: اگر Server Mutationها را انجام ندهیم، می‌توانیم مستقیماً تابع را به عنوان یک prop، مانند هر تابع دیگری منتقل کنیم.

app/posts/[id]/page.js

import LikeButton from './like-button';
 
export default function Page({ params }) {
  async function increment() {
    'use server';
    await updatingDatabase(`post:id:${params.id}`);
  }
 
  return <LikeButton increment={increment} />;
}
app/post/[id]/like-button.jsx

'use client';
 
export default function LikeButton({ increment }) {
  return (
    <button
      onClick={async () => {
        await increment();
      }}
    >
      Like
    </button>
  );
}

جمع‌بندی

Server Actionها در Next.js روشی قدرتمند برای مدیریت data mutationهای سمت سرور، کاهش استفاده از جاوااسکریپت سمت کلاینت و پیشرفت تدریجی فرم‌ها ارائه می‌دهد. با درک و استفاده از Server Actionها، می‌توانیم برنامه‌های وب کارآمدتر و تعاملی ایجاد کنیم.