frontend

إتقان مقابلة عمل React: أهم الأسئلة وأفضل الممارسات

تم التحديث: ٢٧ مارس ٢٠٢٦

Mastering the React Interview top Questions and Best Practices

ملخص

تركز مقابلات React في عام 2026 على مكونات الخادم (Server Components) في React 19 (المستقرة منذ ديسمبر 2024)، والـ Actions، وخطافات (hooks) النماذج الجديدة (useActionState، useOptimistic، useFormStatus)، والـ API use()، وتمرير الـ ref كخاصية (prop)، ومترجم React (Stable v1.0 منذ أكتوبر 2025). كن مستعداً لشرح متى يتم الرندر على الخادم مقابل العميل، وكيف تتعامل الـ Actions مع حالات الانتظار والأخطاء تلقائياً، ولماذا يغير الحفظ التلقائي (automatic memoization) طريقة هيكلتك للمكونات. من المتوقع الإلمام بـ Next.js App Router لأنه الهدف الأكثر شيوعاً لنشر تطبيقات React 19.

تطور React بشكل كبير منذ بداياته. ما كان يعتبر نمطاً متطوراً قبل عامين قد يعتبر اليوم قديماً. إذا كنت تستعد لمقابلة React في عام 2026، فأنت بحاجة إلى فهم ليس فقط الأساسيات — التي لم تتغير — ولكن أيضاً النموذج الحديث: React 19 (المستقر منذ 5 ديسمبر 2024)، ومكونات الخادم، ونموذج الـ Actions، ومترجم React الإصدار 1.0 (المستقر منذ 7 أكتوبر 2025). أضاف إصدار React 19.2 (أكتوبر 2025) مكون <Activity />، و useEffectEvent، والـ Partial Pre-rendering — سيسأل المحاورون في الشركات التي تستخدم أحدث الإصدارات الفرعية عن هذه الميزات أيضاً.

يغطي هذا الدليل الأسئلة التي من المحتمل أن تواجهها، منظمة حسب المفهوم مع إجابات عملية وأمثلة برمجية. سواء كنت تجري مقابلة لأول دور لك في React أو تتقدم لمنصب سينيور، فإن هذه المواضيع تشكل أساس تطوير React الحديث.

فهم التحول الجذري في نموذج React 19 الأساسي

س: ما هو الفرق الجوهري بين مكونات الخادم (Server Components) ومكونات العميل (Client Components)؟

ج: أصبحت مكونات الخادم مستقرة في React 19 (ديسمبر 2024) بعد سنوات في قناة Canary. يتم تنفيذها فقط على الخادم، ولا ترسل أبداً كود JavaScript إلى العميل، ويمكنها الوصول إلى قواعد البيانات والـ APIs والأسرار (secrets) مباشرة. أما مكونات العميل فيتم تنفيذها في المتصفح وهي المكان الوحيد الذي تكون فيه الخطافات (hooks) مثل useState و useEffect صالحة للاستخدام.

في إطار عمل مثل Next.js App Router، تكون مكونات الخادم هي الافتراضية. يمكنك إضافة توجيه 'use client' في الجزء العلوي من الملف لاختيار هذا الموديول (وكل ما يستورده) ليكون ضمن مخطط مكونات العميل:

// app/posts/PostList.tsx — Server Component (default)
export default async function PostList() {
  const posts = await db.posts.findAll();
  return (
    <ul>
      {posts.map(post => <li key={post.id}>{post.title}</li>)}
    </ul>
  );
}
// app/Counter.tsx — Client Component (explicitly marked)
'use client';
import { useState } from 'React';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

لماذا هذا مهم: تقلل مكونات الخادم من حجم كود JavaScript المرسل إلى المتصفح، وتلغي طبقة واحدة من تسلسل جلب البيانات (data-fetching waterfall)، وتسمح ببقاء الأسرار على الخادم. هي ليست بديلاً لمكونات العميل — بل هي مكملة لها.

س: كيف تؤثر مكونات الخادم على جلب البيانات؟

ج: في مكونات الخادم، يمكنك استخدام async/await مباشرة دون الانتقال إلى مسار API. تقوم بجلب البيانات من جهة الخادم قبل الرندر:

// No API route needed
export default async function UserProfile({ userId }) {
  const user = await fetch(`https://API.example.com/users/${userId}`).then(r => r.json());

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
    </div>
  );
}

إذا كان المكون يحتاج إلى تفاعلية (مثل نموذج)، فيمكنك استخراج الجزء التفاعلي في مكون عميل وتمرير البيانات كخصائص (props).

React Actions والتعامل مع النماذج

س: ما هي React Actions ولماذا هي مهمة؟ (وكيف تختلف عن Server Actions؟)

ج: هذا فخ شائع في المقابلات، لذا كن دقيقاً. الـ Actions في React 19 هي دوال غير متزامنة (async) يتم تمريرها إلى انتقالات غير متزامنة (async transitions) — يقوم React بتتبع حالة الانتظار، والتعامل مع الأخطاء عبر حدود الخطأ (Error Boundaries)، ويدعم التحديثات المتفائلة (optimistic updates). تعمل الـ Actions أينما تم تعريفها؛ لا يوجد شيء في الـ Action يتطلب خادماً بالضرورة. أما الـ Server Actions فهي Actions تم تمييزها بتوجيه 'use server'، مما يجعلها قابلة للاستدعاء من مكونات العميل ولكن يتم تنفيذها على الخادم. آلية الـ Action هي نفسها؛ التوجيه هو ما يجعلها مقتصرة على الخادم فقط.

قدم React 19 أيضاً دعماً من الدرجة الأولى لـ <form>: قم بتمرير دالة إلى خاصية action (أو formAction)، وسيقوم React باستدعائها مع بيانات النموذج داخل انتقال (transition).

'use client';
import { createPost } from './actions';

export default function CreatePostForm() {
  return (
    <form action={createPost}>
      <input type="text" name="title" required />
      <textarea name="content" required />
      <button type="submit">Create Post</button>
    </form>
  );
}

وفي ملف actions.ts — هذه هي Server Action:

'use server';
import { db } from '@/lib/db';
import { revalidatePath } from 'next/cache';

export async function createPost(formData: FormData) {
  const title = formData.get('title');
  const content = formData.get('content');

  await db.posts.create({ title, content });
  revalidatePath('/posts');
}

س: كيف تتناسب useActionState و useOptimistic و useFormStatus مع هذا السياق؟

ج: هذه هي الخطافات الثلاثة الجديدة التي تحيط بالـ Actions. معرفة وظيفة كل منها هو سؤال المتابعة الأكثر شيوعاً حول React 19.

  • useActionState(action, initialState) — يغلف الـ Action ويعيد [state, dispatch, isPending]. استخدمه لتتبع نتيجة آخر عملية إرسال وحالة التنفيذ الحالية.
  • useOptimistic(currentState) — يتيح لك رندر تحديث متفائل فوراً بينما لا يزال الـ Action قيد التنفيذ؛ يتراجع React تلقائياً إذا فشل الـ Action.
  • useFormStatus() — يتم استدعاؤه من مكون ابن لـ <form> لقراءة حالة الانتظار للنموذج الأب (يستخدم لتعطيل زر الإرسال أثناء الإرسال، على سبيل المثال).
'use client';
import { useActionState, useOptimistic } from 'React';
import { useFormStatus } from 'React-dom';
import { createPost } from './actions';

function SubmitButton() {
  const { pending } = useFormStatus();
  return <button type="submit" disabled={pending}>{pending ? 'Saving...' : 'Save'}</button>;
}

export default function PostForm({ posts }) {
  const [optimisticPosts, addOptimistic] = useOptimistic(
    posts,
    (state, newPost) => [...state newPost],
  );
  const [error submit] = useActionState(async (_prev formData) => {
    addOptimistic({ title: formData.get('title') pending: true });
    return await createPost(formData);
  } null);

return (
    <form action={submit}>
      <input name="title" required />
      <SubmitButton />
      {error && <p role="alert">{error}</p>}
      <ul>{optimisticPosts.map(p => <li key={ptitle}>{ptitle}</li>)}</ul>
    </form>
  );
}

ملاحظة: يتم استيراد useFormStatus من React-dom، وليس من React. انتبه لهذا التفصيل وستتميز عن الآخرين.

الـ API use() والعمليات غير المتزامنة

س: متى تستخدم الـ API use()؟

ج: use() هي API جديدة (ليست خطافاً أو hook من الناحية التقنية — حيث يمكن استدعاؤها داخل الحلقات التكرارية والجمل الشرطية، على عكس useContext المقيدة بقواعد الخطافات). تقوم بقراءة القيمة من مورد: Promise أو Context. عند استدعائها مع Promise، يتوقف المكون مؤقتاً (suspends) حتى يتم حل الـ Promise، وتظهر أقرب حدود <Suspense> محتواها البديل (fallback).

'use client';
import { use } from 'React';

export default function PostContent({ postPromise }) {
  const post = use(postPromise); // suspends until resolved

  return (
    <article>
      <h1>{posttitle}</h1>
      <p>{postbody}</p>
    </article>
  );
}

يبدأ مكون الخادم عملية الجلب (بدون استخدام await) ويمرر الـ Promise غير المحلول إلى مكون العميل:

import { Suspense } from 'React';
import { PostContent } from './PostContent';

export default function PostPage({ slug }) {
  // No await — kick off the fetch, let the Client Component suspend on it.
  const postPromise = fetch(`https://API.example.com/posts/${slug}`)then(r => rjson());

  return (
    <Suspense fallback={<p>Loading...</p>}>
      <PostContent postPromise={postPromise} />
    </Suspense>
  );
}

يتيح هذا النمط بث البيانات عبر حدود الخادم والعميل دون حظر رندر الخادم.

تعمل use() أيضاً مع الـ Context — وعلى عكس useContext، يمكن استدعاؤها بشكل مشروط (بعد عمليات الإرجاع المبكر، أو داخل فروع if)، وهو أحد الأسباب التي تجعلها لا تُصنف كخطاف (hook).

مترجم React والحفظ التلقائي (Automatic Memoization)

س: ماذا يفعل مترجم React، وهل هو مستقر؟

ج: تم إطلاق مترجم React الإصدار 1.0 كنسخة مستقرة في 7 أكتوبر 2025، بعد حوالي 18 شهراً من المراحل التجريبية والبيتا ونسخ ما قبل الإطلاق. هو عبارة عن إضافة لـ Babel تقوم تلقائياً بحفظ (memoize) المكونات والقيم والدوال المرجعية (callbacks) في وقت البناء، لذا لم تعد بحاجة لاستخدام useMemo أو useCallback أو React.memo يدوياً للتحسينات العادية.

هو اختياري للتطبيقات الحالية ولكنه مفعل افتراضياً في المشاريع الجديدة التي يتم إنشاؤها بواسطة Expo SDK 54+، وقالب Vite React الجديد، وقالب Next.js الجديد (عند اختيار هذا الخيار). هو متوافق مع React 17 وما فوق — لست بحاجة بالضرورة إلى React 19، رغم أن استخدامه مع React 19 هو الحالة الشائعة.

// Before: manual optimization
function ExpensiveComponent({ data onUpdate }) {
  const cachedValue = useMemo(() => processData(data) [data]);
  const cachedCallback = useCallback(() => onUpdate(cachedValue) [cachedValue onUpdate]);

  return <Child value={cachedValue} onChange={cachedCallback} />;
}

// With React Compiler: no optimization code needed
function ExpensiveComponent({ data onUpdate }) {
  const cachedValue = processData(data); // Compiler auto-memoizes
  const cachedCallback = () => onUpdate(cachedValue); // Auto-memoized callback

  return <Child value={cachedValue} onChange={cachedCallback} />;
}

أسئلة متابعة متوقعة: "هل ما زلت بحاجة إلى useMemo؟" (بشكل عام لا داخل الكود المترجم، ولكن نعم لعزل الحسابات المكلفة جداً أو عندما يتوقف المترجم عن العمل بسبب أنماط ديناميكية.) "كيف تتبناه تدريجياً؟" (لكل مجلد أو لكل ملف عبر إعدادات المترجم — راجع دليل التبني التدريجي الرسمي.)

الـ ref كخاصية (prop)، و forwardRef

س: كيف تعمل الـ refs في React 19؟

ج: في React 19، تقبل مكونات الدوال الـ ref كخاصية عادية. لم تعد هناك حاجة لـ forwardRef للمكونات الجديدة وسيتم إهمالها في إصدار رئيسي مستقبلي:

// React 19: ref is just a prop
function MyInput({ placeholder ref }) {
  return <input placeholder={placeholder} ref={ref} />;
}

// Usage stays the same
<MyInput ref={inputRef} />

يجب أن تظل قادراً على التعرف على forwardRef لأن كل قاعدة كود أقدم من أواخر عام 2024 تستخدمها. أضاف React 19 أيضاً دعماً لـ دوال تنظيف الـ ref — إذا أعادت دالة استدعاء الـ ref دالة أخرى، فسيقوم React باستدعائها عند إلغاء تحميل المكون (unmount)، مما يحاكي دلالات التنظيف في useEffect.

أنماط Next.js App Router

س: كيف تنظم ميزة كاملة (full-stack feature) في Next.js App Router؟

ج: النمط هو: مكون خادم ← مكون عميل للتفاعلية ← Action للعمليات التي تغير البيانات (mutations) ← إعادة التحقق من الكاش (Cache revalidation).

// app/posts/page.tsx - Server Component
import { PostList } from './components/PostList';

export default async function PostsPage() {
  const posts = await db.posts.findAll();

return (
    <div>
      <h1>Posts</h1>
      <PostList initialPosts={posts} />
    </div>
  );
}

// components/PostList.tsx - Client Component
'use client';
import { useState } from 'React';
import { deletePost } from '../actions';

export function PostList({ initialPosts }) {
  const [posts, setPosts] = useState(initialPosts);

  async function handleDelete(id) {
    await deletePost(id);
    setPosts(posts.filter(p => p.id !== id));
  }

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          {post.title}
          <button onClick={() => handleDelete(post.id)}>Delete</button>
        </li>
      ))}
    </ul>
  );
}

// actions.ts
'use server';
import { db } from '@/lib/db';
import { revalidatePath } from 'next/cache';

export async function deletePost(id: string) {
  await db.posts.delete(id);
  revalidatePath('/posts');
}

الأنماط القديمة (لا تزال تُسأل)

س: ما هي مكونات الفئات (class components) ومتى تظل ذات صلة؟

ج: مكونات الفئات هي الطريقة التي كانت تُستخدم قبل الـ hooks لإدارة الحالة (state) والآثار الجانبية (side effects). نادراً ما تُستخدم في الأكواد الجديدة ولكنها تظهر في قواعد الأكواد القديمة:

class Counter extends React.Component {
  state = { count: 0 };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment
        </button>
      </div>
    );
  }
}

المكونات الوظيفية (Functional components) مع الـ hooks هي المعيار الحديث. إذا واجهت مكونات فئات في مقابلة عمل، أظهر أنك تفهمها ولكن ركز على الأساليب المعتمدة على الـ hooks.

س: ما الفرق بين useEffect وجلب البيانات من جانب الخادم (server-side data fetching)؟

ج: useEffect يعمل في المتصفح بعد الرندر. إذا كان بإمكانك جلب البيانات من جانب الخادم (في Server Component أو Action)، فيجب عليك ذلك — فهو أسرع ولا يتسبب في شلال تحميل (loading waterfall):

// أبطأ: جلب من جانب العميل مع شلال تحميل
'use client';
import { useEffect, useState } from 'React';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/API/users/${userId}`)
      .then(r => r.json())
      .then(setUser);
  }, [userId]);

  return user ? <p>{user.name}</p> : <p>Loading...</p>;
}

// أسرع: جلب من جانب الخادم
export default async function UserProfile({ userId }) {
  const user = await fetch(`https://API.example.com/users/${userId}`).then(r => r.json());
  return <p>{user.name}</p>;
}

إضافات React 19.2 التي تستحق المعرفة

تم إطلاق React 19.2 في 1 أكتوبر 2025. اعتمدت معظم الفرق التي تستخدم أحدث إصدار فرعي واحدة على الأقل من هذه الميزات.

  • <Activity /> — يقوم بعمل رندر مسبق أو يحافظ على حالة واجهة المستخدم لأجزاء التطبيق التي من المحتمل أن ينتقل إليها المستخدم (أو يبتعد عنها)، دون إلغاء التثبيت (unmounting). يحل محل الكثير من أنماط "اجعل هذا مثبتاً ولكن مخفياً" اليدوية.
  • useEffectEvent — يفصل منطق نمط الحدث (event-style logic) عن الـ Effect التفاعلي. الوظيفة الناتجة ترى دائماً أحدث الـ props/state دون إعادة تشغيل الـ Effect عند تغيرها. يحل مشكلة "stale closure داخل useEffect" بشكل نظيف.
  • Partial Pre-rendering — رندر مسبق للهيكل الثابت (static shell)، وبث الأجزاء الديناميكية لاحقاً. ذو صلة خاصة إذا ذكر المحاور PPR في Next.js.
  • Suspense SSR Batching — يتم الكشف عن حدود Suspense التي تم عمل رندر لها على الخادم في دفعات، مما يحسن تجربة التحميل المدركة.
  • cacheSignal — لـ Server Components، وهو AbortSignal يتم إطلاقه عندما لا تعود هناك حاجة لمورد مخزن مؤقتاً.

مواضيع المقابلات الشائعة

نظرة عامة على React Hooks (React 19.2):

  • useState: إدارة الحالة
  • useEffect: الآثار الجانبية والتنظيف
  • useEffectEvent (19.2): معالجات أحداث غير تفاعلية داخل الـ Effects
  • useContext: قراءة السياق (ملاحظة: use(Context) يعمل بشكل مشروط)
  • useReducer: منطق الحالة المعقد
  • useCallback / useMemo: التخزين المؤقت اليدوي (غالباً ما يكون غير ضروري مع React Compiler)
  • useRef: الوصول إلى عناصر DOM أو التخزين القابل للتغيير
  • useTransition: وضع علامة على تحديثات الحالة كغير عاجلة
  • useDeferredValue: تأجيل رندر قيمة مكلفة
  • useActionState (19): حالة الانتظار/النتيجة للـ Actions
  • useOptimistic (19): واجهة مستخدم متفائلة أثناء الانتقالات غير المتزامنة
  • useFormStatus (19، من React-dom): قراءة حالة الانتظار للنموذج الأب
  • use() (19): قراءة Promise أو Context، ويمكن استدعاؤه بشكل مشروط

تحسين الأداء:

  • اعتماد React Compiler بدلاً من كتابة useMemo/useCallback يدوياً
  • تقسيم الكود (Code splitting) مع الاستيراد الديناميكي و React.lazy
  • تحسين الصور (AVIF, WebP) ومكون <Image> الخاص بإطار العمل
  • تحليل الحزمة (Bundle analysis) باستخدام (rollup-plugin-visualizer لـ Vite، أو @next/bundle-analyzer لـ Next.js)
  • التحميل الكسول (Lazy loading) مع حدود Suspense
  • React DevTools Profiler لتحديد عمليات الرندر المكلفة

أفضل ممارسات الاختبار:

  • اختبارات الوحدة (Unit tests) باستخدام Vitest أو Jest
  • اختبار المكونات باستخدام React Testing Library
  • اختبارات التكامل (Integration tests) للميزات الكاملة
  • اختبارات النهاية للنهاية (E2E tests) باستخدام Playwright أو Cypress

ملخص

React في عام 2026 يدور بشكل أساسي حول الرندر المعتمد على الخادم أولاً مع تفاعلية تدريجية. يتوقع المحاورون منك توضيح نموذج React 19 — الـ Server Components مستقرة، الـ Actions هي الأداة الأساسية الجديدة للتعديل، use() يقرأ الـ Promises والـ Context، الـ refs أصبحت props عادية، و React Compiler (الإصدار 1.0، أكتوبر 2025) يتولى التخزين المؤقت (memoization) نيابة عنك. أضاف React 19.2 (أكتوبر 2025) ميزات <Activity />، و useEffectEvent، و Partial Pre-rendering — معرفة هذه الأمور تشير إلى أنك مطلع على أحدث التطورات.

كن دقيقاً بشأن الحدود بين الـ Actions (أداة الانتقال في React 19) والـ Server Actions (الـ Actions بالإضافة إلى 'use server'). كن صادقاً بشأن ما يمكن وما لا يمكن للـ Server Components فعله — فهي ليست بديلاً كاملاً للـ Client Components، والقيمة تأتي من استخدام كل منهما في مكانه المناسب.

أتقن هذه المفاهيم الأساسية، وافهم App Router الخاص بـ Next.js، وكن مستعداً لمناقشة كل من الأنماط الحديثة والكود القديم. يريد المحاورون رؤية أنك تفهم لماذا توجد خيارات معينة، وليس فقط كيفية كتابة الكود.

المصادر