ویرگول
ورودثبت نام
مصطفی رستگار
مصطفی رستگاربرنامه نویس کامپیوتر و ازین جور مسخره بازی ها!
مصطفی رستگار
مصطفی رستگار
خواندن ۵ دقیقه·۳ ماه پیش

Server Components vs Client Components در Next.js

بخش اول: معرفی کلی

«در Next.js 13 به بعد، ما با دو نوع کامپوننت مواجه هستیم: Server Components و Client Components. این معماری به ما اجازه میدهد بهترین عملکرد را داشته باشیم: سرعت بالا، امنیت بهتر، و تجربه کاربری روان. نکته کلیدی این است که همه کامپوننتها به صورت پیشفرض Server هستند و فقط وقتی نیاز به تعامل داریم، با 'use client' آنها را به Client تبدیل میکنیم.»


بخش دوم: Server Components (کامپوننتهای سروری)

تعریف:

«کامپوننتهایی که روی سرور رندر میشوند و خروجی HTML به مرورگر فرستاده میشود. اینها پیشفرض Next.js هستند و نیازی به نشانهگذاری خاصی ندارند.»

مزایا (۴ مورد کلیدی):

  1. سرعت بارگذاری: چون کد جاوااسکریپت کمتری به مرورگر میرود، صفحه سریعتر لود میشود

  2. SEO بهتر: موتورهای جستجو محتوای کامل HTML را میبینند

  3. دسترسی مستقیم به دیتابیس: بدون نیاز به API، مستقیماً با دیتابیس ارتباط برقرار میکنند

  4. امنیت بیشتر: کدهای حساس مثل توکنها و کلیدهای API هرگز به کلاینت نمیروند

مثال کاربردی:

«فرض کنید لیست محصولات را از دیتابیس میخوانیم. این کار را در Server Component انجام میدهیم چون نیازی نیست کاربر منتظر بارگذاری جاوااسکریپت بماند و اطلاعات مستقیم از سرور میآید.»

javascript

// ✅ Server Component (پیشفرض) export default async function ProductList() { const products = await db.products.findMany(); return ( <div> {products.map(p => <ProductCard key={p.id} {...p} />)} </div> ); }

بخش سوم: Client Components (کامپوننتهای کلاینت)

تعریف:

«کامپوننتهایی که با 'use client' مشخص میشوند و روی مرورگر اجرا میشوند. اینها برای تعاملات کاربری ضروری هستند.»

چه زمانی استفاده کنیم؟ (۳ موقعیت):

  1. تعاملات کاربری: کلیک، hover، تغییر state

  2. استفاده از Hookهای React: useState، useEffect، useContext

  3. APIهای مرورگر: localStorage، window، document

مثال کاربردی:

«فرم افزودن تسک که کاربر در آن تایپ میکند و دکمه میزند، باید Client Component باشد.»

javascript

'use client'; // ✅ Client Component import { useState } from 'react'; export default function AddTodoForm() { const [title, setTitle] = useState(''); return ( <input value={title} ={(e) => setTitle(e.target.value)} /> ); }

بخش چهارم: Server Actions ('use server')

تعریف:

«توابعی که با 'use server' علامتگذاری میشوند و فقط روی سرور اجرا میشوند، اما میتوان آنها را از Client Components صدا زد.»

کاربردهای اصلی (۳ مورد):

  1. عملیات امن: ثبتنام، ورود، آپدیت دیتابیس

  2. جایگزین API: بدون نیاز به نوشتن REST API یا GraphQL

  3. مدیریت داده: افزودن، ویرایش، حذف اطلاعات

مثال کاربردی:

«وقتی کاربر فرم ثبتنام را پر میکند، به جای ارسال به API عمومی، یک Server Action صدا میزنیم که مستقیماً با دیتابیس ارتباط برقرار میکند.»

javascript

'use server'; // ✅ Server Action export async function addTodo(formData) { const title = formData.get('title'); await db.todo.create({ data: { title } }); revalidatePath('/'); // بازسازی صفحه return { success: true }; }

بخش پنجم: جدول مقایسه سریع


بخش ششم: روشهای مدیریت Form (نکته کلیدی)

«برای مدیریت فرمها در Next.js، سه روش داریم که هر کدام کاربرد خاص خود را دارند:»

۱. روش ساده (useFormStatus + useFormState):

«برای فرمهای ساده با یک دکمه Submit، از هوکهای useFormStatus و useFormState استفاده میکنیم. این روش خودکار loading و error را مدیریت میکند.»

javascript

'use client'; import { useFormState, useFormStatus } from 'react-dom'; function SubmitButton() { const { pending } = useFormStatus(); // ✅ خودکار return <button disabled={pending}>ارسال</button>; } function Form() { const [state, formAction] = useFormState(addTodo, initialState); return ( <form action={formAction}> <input name="title" /> <SubmitButton /> {state?.error && <p>{state.error}</p>} </form> ); }

۲. روش انعطافپذیر (useTransition):

«برای عملیاتهای پیچیدهتر مثل چندین دکمه مختلف در یک صفحه، یا عملیات دستهای، از useTransition استفاده میکنیم. این روش کنترل کامل روی loading و error میدهد و اجازه میدهد چندین عملیات مجزا داشته باشیم.»

javascript

'use client'; import { useTransition } from 'react'; function BulkActions() { const [isDeleting, startDelete] = useTransition(); const [isCompleting, startComplete] = useTransition(); return ( <> <button ={() => startDelete(deleteAll)} disabled={isDeleting}> {isDeleting ? 'در حال حذف...' : 'حذف همه'} </button> <button ={() => startComplete(completeAll)} disabled={isCompleting}> {isCompleting ? 'در حال تکمیل...' : 'تکمیل همه'} </button> </> ); }

۳. چه موقع از کدام روش استفاده کنیم؟

سناریوروش مناسبفرم ثبتنام سادهuseFormStatus + useFormStateفرم با چندین دکمه مختلفuseTransitionعملیات دستهای (حذف گروهی)useTransitionناوبری بین صفحاتuseTransition + useRouterآپدیتهای سنگین UIuseTransitionفرم با اعتبارسنجی پیچیدهuseFormState + اعتبارسنجی در Server Action


بخش هفتم: بهترین روشها (Best Practices)

«۵ اصل مهم که همیشه رعایت میکنم:»

  1. تا جایی که ممکن است از Server Components استفاده کنید و فقط بخشهای تعاملی را Client کنید

  2. دادههای حساس را در Server Actions نگهداری کنید، نه در Client Components

  3. برای فرمهای ساده از useFormStatus و useFormState و برای عملیات پیچیده از useTransition استفاده کنید

  4. از revalidatePath یا revalidateTag بعد از هر تغییر داده استفاده کنید تا صفحه آپدیت شود

  5. همیشه اعتبارسنجی را در Server Action انجام دهید، حتی اگر در کلاینت هم انجام میدهید (امنیت)


بخش هشتم: جمعبندی نهایی برای مصاحبه (۳۰ ثانیه)

«در Next.js مدرن، استراتژی من این است: همه چیز را Server Component شروع میکنم. اگر به تعامل کاربری نیاز داشت، با 'use client' آن بخش را به Client تبدیل میکنم. برای عملیاتهای امن روی داده، از 'use server' استفاده میکنم. برای مدیریت فرمها، اگر ساده است از useFormStatus و useFormState و اگر پیچیده است از useTransition استفاده میکنم. این رویکرد به من میدهد: سرعت بالا، امنیت عالی، و تجربه کاربری روان، بدون اینکه مجبور باشم بین SSR و SPA یکی را انتخاب کنم.»


بخش نهم: پاسخ به سوالات احتمالی مصاحبه

"چرا Next.js این مدل را انتخاب کرده؟"

«برای ترکیب بهترینهای SSR (سرعت و SEO) با SPA (تعامل پذیری). با این روش، میتوانیم هم صفحات سریع داشته باشیم و هم اپلیکیشنهای پویا و تعاملی بسازیم، بدون اینکه مجبور باشیم یکی را فدا کنیم.»

"آیا میتوانیم Server Component را داخل Client Component استفاده کنیم؟"

«خیر. اگر یک کامپوننت را 'use client' کنیم، تمام زیرکامپوننتهای آن هم Client میشوند، مگر اینکه به صورت children یا prop از بالا ارسال شوند. بهترین روش این است که کامپوننتهای تعاملی را در لایههای بالایی قرار دهیم و دادهها را از Server Components به آنها پاس دهیم.»

"چطور خطاها را در Server Actions مدیریت میکنیم؟"

«با useFormState خطاها به صورت خودکار مدیریت میشوند. با useTransition از try/catch استفاده میکنیم. همچنین میتوانیم از error.tsx در Next.js برای نمایش خطاهای سرور استفاده کنیم.»

"چه موقع از useTransition به جای useFormStatus استفاده کنیم؟"

«useFormStatus فقط در فرمهای ساده با یک دکمه Submit کار میکند. اما اگر چندین دکمه در یک صفحه داریم (مثل حذف گروهی، تکمیل گروهی، فیلتر کردن) یا میخواهیم ناوبری نرم داشته باشیم، از useTransition استفاده میکنیم که کنترل بیشتری به ما میدهد.»


📝 بخش دهم: جمعبندی نهایی

مفهومیک خط توضیحServer Componentرندر روی سرور، پیشفرض، بدون 'use client'Client Componentرندر روی مرورگر، برای تعامل، با 'use client'Server Actionاجرا روی سرور، با 'use server'، برای عملیات امنuseFormStatusمدیریت خودکار loading در فرمهای سادهuseFormStateمدیریت خودکار state و error در فرمهاuseTransitionمدیریت عملیات غیرهمزمان پیچیده و چندگانه


نکته نهایی برای مصاحبه:

«با این رویکرد، من نه تنها کد تمیز و مدرن مینویسم، بلکه اپلیکیشنی میسازم که هم برای کاربران سریع است، هم برای توسعهدهندگان قابل نگهداری، و هم برای کسبوکار امن و مقیاسپذیر.»


reactمصاحبه فنی
۲
۰
مصطفی رستگار
مصطفی رستگار
برنامه نویس کامپیوتر و ازین جور مسخره بازی ها!
شاید از این پست‌ها خوشتان بیاید