Menu
flag Ar iconالعربيةdown icon

الوضع الصارم في React: لماذا تعمل التأثيرات والعروض مرتين

StrictMode مغلّف للتطوير فقط يعرض المكوّنات مرتين، ويشغّل عند التركيب إعداد التأثيرات ثم تنظيفها ثم إعدادها من جديد، ويحذّر من الواجهات المُهملة، فيظهر العرض غير النقي والتنظيف المفقود مبكرًا. ولا يفعل شيئًا في الإنتاج.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

<StrictMode> مكوّن في React يفعّل فحوصًا إضافية لكل ما بداخله، في التطوير فقط. يعرض كل مكوّن مرتين، ويشغّل عند التركيب إعداد كل تأثير ثم تنظيفه ثم إعداده من جديد، ويشغّل دوال المرجع مرتين، ويحذّر من الواجهات المُهملة. ولهذا «يعمل useEffect مرتين» في التطوير. أما في بناء الإنتاج فلا يفعل شيئًا.

تفعّله بتغليف تطبيقك، عادة في main.jsx:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';

createRoot(document.getElementById('root')).render(
    <StrictMode>
        <App />
    </StrictMode>,
);

تعمل المعاينات في هذه الصفحة مثل بناء الإنتاج، فلن يكون لـ StrictMode أثر مرئي فيها. بدلًا من ذلك، يحتوي كل مثال أدناه على نوع الخطأ الذي وُجد StrictMode لالتقاطه، ويتيح لك إطلاقه يدويًا. هنا يضيف تأثير مستمع نقرات على document ولا يزيله أبدًا. أخفِ اللوحة وأظهرها مرتين، ثم انقر في الصفحة.

كل Show يضيف مستمعًا آخر، ولا يُزال أي منها، فتسجّل النقرة الواحدة مرة لكل تركيب. هذا تسرّب قد يسببه مستخدم بفتح لوحة وإغلاقها. وكان StrictMode سيُظهره من أول تركيب: في التطوير يركّب ثم يزيل ثم يركّب من جديد، فكنت سترى سطري سجل لكل نقرة قبل أن تلمس الزر.

التأثيرات: إعداد، تنظيف، إعداد

عند التركيب، يشغّل StrictMode تأثيرك، ثم تنظيفه، ثم التأثير من جديد. إنه يحاكي ما يحدث عندما يغادر المستخدم شاشة ويعود، ويتحقق من أن تنظيفك يلغي إعدادك. إن كان كذلك، فالإعداد الثاني يترك الأمور تمامًا كما يتركها إعداد واحد، ولا ترى أي خطأ. وإن لم يكن، يظهر الخطأ فورًا.

إصلاح المسجّل دالة تنظيف تزيل الدالة نفسها التي أضافها:

بدّل كما تشاء: كل نقرة تسجّل سطرًا واحدًا ما دام المسجّل ظاهرًا. ومع StrictMode في التطوير ستبدأ وحدة التحكم بـ setup وcleanup وsetup، وسيظل التطبيق يتصرف بشكل صحيح. هذا التسلسل علامة على تأثير سليم، لا مشكلة عليك إطفاؤها.

تأثيرات شائعة تحتاج إلى تنظيف: مستمعو الأحداث، وsetInterval وsetTimeout، والاشتراكات، واتصالات WebSocket أو المحادثة، والطلبات التي ينبغي تجاهل ردها إذا زال المكوّن. تُظهر صفحة useEffect نمط التنظيف لكل منها.

مرات العرض: استدعاء مزدوج

يستدعي StrictMode أيضًا دالة مكوّنك مرتين في كل عرض (والدوال التي تمررها إلى useState وuseMemo وuseReducer، وconstructor وrender وshouldComponentUpdate في الأصناف). تحتفظ React بنتيجة استدعاء واحد وترمي الآخر. المكوّن النقي يُرجع JSX نفسها في المرتين، فلا يتغير شيء.

أما المكوّن الذي يغيّر شيئًا خارجه أثناء العرض فليس نقيًا، واستدعاؤه مرتين يجعل التغيير يحدث مرتين. هذا المكوّن يضيف مدخل "rendered at" إلى مصفوفة يستقبلها كـ prop:

كل إعادة عرض تضيف مدخلًا لم يطلبه أحد. هنا لا تلاحظ إلا بعد النقر. ومع StrictMode كان العرض الأول سيُظهر أصلًا مدخلين جديدين بدلًا من واحد. والإصلاح هو الحساب أثناء العرض دون تعديل: const shown = [...entries, 'extra'].

تضيف React 19 تفصيلًا واحدًا: أثناء العرض المزدوج، يعيد useMemo وuseCallback استخدام النتيجة من الاستدعاء الأول بدلًا من حسابها مرتين.

دوال المرجع

منذ React 19، يشغّل StrictMode أيضًا دوال المرجع مرتين عند التركيب: ربط، ثم تنظيف، ثم ربط. دالة المرجع التي تضيف مستمعًا أو تسجّل العقدة في مكان ما تحتاج إلى إرجاع دالة تنظيف، تمامًا مثل التأثير:

<div
    ref={(node) => {
        const observer = new ResizeObserver(onResize);
        observer.observe(node);
        return () => observer.disconnect();
    }}
/>

تحذيرات الواجهات المُهملة

يحذّر StrictMode من الواجهات في طريقها إلى الزوال، في مكوّنات الأصناف غالبًا، مثل توابع دورة الحياة القديمة UNSAFE_componentWillMount وUNSAFE_componentWillReceiveProps وUNSAFE_componentWillUpdate. وبعض الواجهات التي كان يحذّر منها، مثل مراجع النصوص وfindDOMNode، حُذفت من React 19 كليًا.

تفعيله لجزء من التطبيق

<StrictMode> مكوّن عادي، فيمكنك تغليف جزء من الشجرة فقط. وهذا يفيد عند تبنّيه في تطبيق كبير: ابدأ بالشاشات الجديدة ثم وسّع.

function App() {
    return (
        <>
            <Header />
            <StrictMode>
                <Sidebar />
                <Content />
            </StrictMode>
            <Footer />
        </>
    );
}

يحصل Sidebar وContent (وكل ما يعرضانه) على الفحوص؛ ولا يحصل عليها Header وFooter. ولا توجد طريقة لإطفائه لشجرة فرعية داخل جزء صارم.

أين يكون مفعّلًا افتراضيًا:

  • Vite: يغلّف قالب React المكوّن <App /> بـ <StrictMode> في main.jsx.
  • Next.js: يفعّله App Router افتراضيًا؛ ويتحكم فيه reactStrictMode في next.config.js.

لا يفعل شيئًا في الإنتاج

يتجاهل بناء الإنتاج <StrictMode>: عرض واحد، وتشغيل واحد للتأثير، ولا تحذيرات. لذا لا تكلّف الاستدعاءات المزدوجة مستخدميك شيئًا أبدًا، ولا سبب لحذف المغلّف قبل النشر.

إذا كسر تأثير مزدوج شيئًا في التطوير، مثل طلب يُرسل مرتين أو حدث تحليلات يُسجَّل مرتين، فتلك معلومة. وفي معظم الأحيان يكون الإصلاح دالة تنظيف (علامة ignore لطلب، أو قطع اتصال لاتصال). أما لشيء يجب فعلًا أن يحدث مرة واحدة لكل تحميل للتطبيق، مثل تهيئة SDK، فشغّله خارج أي مكوّن على مستوى الوحدة، أو احمِه بعلامة على مستوى الوحدة.

let didInit = false;

function App() {
    useEffect(() => {
        if (didInit) return;
        didInit = true;
        initAnalytics(); // runs once per page load, even in StrictMode
    }, []);
}

تجنّب الحل الالتفافي الشائع بمرجع يتخطى التشغيل الثاني للتأثير. فهو يخفي التحذير دون إصلاح التنظيف المفقود، ويعود الخطأ في أول مرة يُزال فيها المكوّن ويُركَّب من جديد فعلًا، كما يحدث مع المسجّل أعلاه.

الأسئلة الشائعة

ماذا يفعل StrictMode في React؟

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

لماذا يعمل useEffect الخاص بي مرتين؟

لأن المكوّن داخل <StrictMode> وأنت تشغّل بناء تطوير. تركّبه React، ثم تحاكي إزالته (فتعمل دالة التنظيف)، ثم تركّبه من جديد. إذا سبب الإعداد الثاني خطأ، فالتأثير ينقصه تنظيف.

هل يؤثر StrictMode في الإنتاج؟

لا. بناء الإنتاج يعرض مرة واحدة ويشغّل كل تأثير مرة واحدة، مع <StrictMode> أو بدونه. يمكنك تركه في كودك.

كيف أعطّل StrictMode؟

احذف المغلّف <StrictMode>، عادة في main.jsx أو index.js، أو اضبط reactStrictMode: false في next.config.js. لكن إصلاح التنظيف أفضل عادة: التشغيل المزدوج يشير إلى خطأ قد يصادفه مستخدمون حقيقيون.

لماذا يُطبع console.log مرتين؟

يستدعي StrictMode دالة مكوّنك مرتين في كل عرض أثناء التطوير. ويمكن لـ React DevTools أن تجعل سجلات الاستدعاء الثاني باهتة، أو تخفيها، من إعداداتها.

رسم توضيحي للغات البرمجة في Coddy

تعلّم البرمجة مع Coddy

ابدأ الآن