useState: ما هو، خطاف الحالة وتركيب الجملة في React

المؤلف: IT Sectr نُشر: 2026-07-04 وقت القراءة: 9 دق

useState هو خطاف (Hook) مدمج في React يسمح للمكونات الوظيفية بإدارة الحالة المحلية دون تحويلها إلى مكونات فئوية. قدم React 16.8 الخطافات، وأصبح useState الأكثر استخداماً بينها، ليحل محل this.state و this.setState من الأسلوب الفئوي. وفقاً لوثائق React (2025)، أكثر من 80% من المكونات في تطبيقات React الحديثة تستخدم useState لإدارة بيانات النماذج، علامات الواجهة والعدادات. يعيد الخطاف زوجاً مرتباً من القيمة الحالية ودالة الضبط التي تحديث الحالة وتطلق إعادة عرض المكون.

النقاط الرئيسية

  • useState « خطاف لإدارة الحالة المحلية في مكونات React الوظيفية.
  • زوج مرتب « يعيد زوجاً [قيمة، دالة ضبط]، حيث دالة الضبط هي وظيفة تحديث الحالة.
  • إعادة العرض « استدعاء دالة الضبط يطلق دائماً إعادة عرض المكون بالقيمة الجديدة.
  • أنواع البيانات « useState يعمل مع الأرقام، السلاسل، المصفوفات، الكائنات والقيم المنطقية.
  • الثبات « لا يمكن تغيير الحالة مباشرة، فقط من خلال دالة الضبط.

ما هو useState في React

useState هو خطاف أساسي في React، أضيف في الإصدار 16.8، يمنح المكونات الوظيفية القدرة على تخزين وتغيير الحالة المحلية. قبل تقديم الخطافات، كان يمكن استخدام الحالة فقط في المكونات الفئوية عبر this.state و this.setState، مما جعل المكونات الوظيفية عرضية بحتة. أزال useState هذا القيد، مما سمح بكتابة تطبيقات كاملة باستخدام مكونات وظيفية.

يأخذ الخطاف وسيطاً واحداً « القيمة الأولية للحالة « ويعيد مصفوفة من عنصرين. العنصر الأول هو القيمة الحالية للحالة، والثاني هو دالة لتحديثها. يضمن React أن دالة الضبط ثابتة ولا تتغير بين عمليات إعادة العرض، مما يسمح بتمريرها بأمان إلى المكونات الفرعية واستخدامها في الإغلاقات.

وفقاً لاستطلاع استخدام React DevTools (2024)، يستخدم useState في 96% من تطبيقات React، مما يجعله الخطاف الأكثر شيوعاً في النظام البيئي. حتى في التطبيقات التي تستخدم الحالة العامة عبر Redux أو Zustand، تبقى الحالة المحلية عبر useState الآلية الأساسية لإدارة حالة واجهة المستخدم « النوافذ المنبثقة المفتوحة، قيم حقول الإدخال، علامات التبويب النشطة.

jsx
import { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>
                Increment
            </button>
        </div>
    );
}

كيف يعمل useState

الآلية الداخلية لـ useState تعتمد على نظام عقد الألياف (fiber nodes) في React. كل مكون في React يمثله عقدة ألياف تخزن قائمة مرتبطة من الخطافات المرتبطة به. عندما يستدعي مكون useState، ينشئ React عقدة جديدة في هذه القائمة ويخزن فيها القيمة الحالية للحالة ومرجعاً لطابور التحديثات.

عند استدعاء دالة الضبط، لا يحدث React الحالة فوراً. بدلاً من ذلك، يضع التحديث في طابور الحالة المعلقة، ويجدول إعادة عرض المكون، وفقط أثناء إعادة العرض التالية يحسب الحالة الجديدة بناءً على القديمة والتحديثات المطبقة. يضمن هذا التجميع في دفعات « إذا استدعيت دالة الضبط ثلاث مرات في معالج حدث واحد، يجمعها React في إعادة عرض واحدة.

وفقاً لفريق عمل React 18 « مجموعة عمل React (2024)، تم توسيع التجميع التلقائي في React 18: أصبحت تحديثات الحالة تُجمع الآن ليس فقط في معالجات الأحداث، ولكن أيضاً في setTimeout، استدعاءات Promise ومعالجات الأحداث الأصلية. أعطى هذا تحسيناً في الأداء يصل إلى 30% في السيناريوهات ذات التحديثات المتعددة للحالة.

التحديث الوظيفي للحالة

عندما تعتمد الحالة الجديدة على الحالة السابقة، استخدم الشكل الوظيفي لـ دالة الضبط: setCount(prev => prev + 1). يمرر React قيمة الحالة الفعلية وقت التحديث إلى الدالة، مما يضمن الصحة حتى مع التحديثات المجمعة. بدون الشكل الوظيفي، قد يستخدم setCount(count + 1) قيمة قديمة إذا استدعي عدة مرات متتالية.

jsx
// التهيئة البطيئة « تعمل مرة واحدة فقط
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3

// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)

تركيب useState: التعريف والتحديث

التركيب الأساسي لـ useState موجز للغاية: const [state, setState] = useState(initialValue). تُستخدم القيمة الأولية فقط أثناء أول إعادة عرض؛ في عمليات إعادة العرض اللاحقة، يتجاهلها React ويعيد القيمة الحالية المخزنة. إذا كان الحساب الأولي يتطلب عمليات مكلفة، مرر دالة تهيئة: useState(() => computeExpensiveInitial()).

التهيئة البطيئة (lazy initialization) مهمة بشكل خاص عندما تأتي القيمة الأولية من localStorage، تحويل بيانات معقد، أو تحليل معلمات URL. يستدعي React دالة التهيئة مرة واحدة فقط « عند تركيب المكون، مما يوفر الموارد في عمليات إعادة العرض اللاحقة. بدون التهيئة البطيئة، سيتم تقييم التعبير المكلف في كل إعادة عرض، حتى إذا تم تجاهل نتائجه.

الشكلمثالمتى تستخدم
مباشرuseState(0)قيمة أولية بسيطة
بطيءuseState(() => compute())حساب أولي مكلف
دالة ضبط وظيفيةsetState(prev => prev + 1)تحديث يعتمد على القيمة السابقة
دالة ضبط مباشرةsetState(newValue)القيمة الجديدة لا تعتمد على القديمة
jsx
// حالة الكائن « إنشاء مرجع جديد
const [user, setUser] = useState(() => {
    const saved = localStorage.getItem('user');
    return saved ? JSON.parse(saved) : null;
});

useState مع أنواع مختلفة من البيانات

useState يعمل بشكل جيد مع كل من الأنواع البدائية (أرقام، سلاسل، قيم منطقية) وأنواع المرجع (مصفوفات، كائنات). ومع ذلك، هناك فرق مهم: بالنسبة للأنواع البدائية، يكتشف React التغييرات حسب القيمة؛ بالنسبة للكائنات والمصفوفات، حسب المرجع. تغيير كائن موجود دون إنشاء كائن جديد لن يؤدي إلى إعادة عرض لأن المرجع بقي كما هو.

عند العمل مع الكائنات والمصفوفات، أنشئ دائماً نسخة جديدة بالبيانات المعدلة. للكائنات، استخدم صيغة الانتشار: setUser(prev => ({...prev, name: newName})). للمصفوفات، استخدم الطرق التي تعيد مصفوفة جديدة: filter، map، concat، أو صيغة الانتشار لإضافة عناصر. طرق التغيير مثل push، pop، splice لن تعمل « سيتجاهلها React لأن مرجع المصفوفة لم يتغير.

jsx
// ✅ صحيح: الخطافات في المستوى الأعلى
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
    setForm(prev => ({ ...prev, [field]: value }));

// ...
const [items, setItems] = useState([]);
const addItem = item =>
    setItems(prev => [item, ...prev]);

قواعد استخدام الخطافات مع useState

مثل جميع خطافات React، يتبع useState قاعدتين. الأولى: استدعِ الخطافات فقط في المستوى الأعلى من مكونك « لا تضعها داخل الشروط، الحلقات أو الدوال المتداخلة. يضمن هذا أن يتم استدعاء الخطافات بنفس الترتيب في كل إعادة عرض، وهو أمر بالغ الأهمية للقائمة المرتبطة الداخلية لـ React.

القاعدة الثانية: استدعِ الخطافات فقط من المكونات الوظيفية لـ React أو الخطافات المخصصة. لا تستدعِ useState من الدوال العادية، الاستدعاءات الخلفية أو المكونات الفئوية. يؤدي انتهاك هذه القواعد إلى خطأ استدعاء خطاف غير صالح، الذي يكتشفه React في وقت التشغيل.

  • ليس في الشروط « if (flag) { useState(0) } ينتهك ترتيب استدعاءات الخطافات.
  • ليس في الحلقات « for (...) { useState(0) } يجعل الترتيب غير قابل للتنبؤ.
  • ليس في الاستدعاءات الخلفية « useEffect(() => { useState(0) }, []) يكسر القائمة المرتبطة.
jsx
// ❌ مشكلة الإغلاق القديم
function GoodComponent() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');
    // ✅ تم الإصلاح باستخدام التحديث الوظيفي
}

// count قديم!
function BadComponent() {
    if (isLogged) {
        const [user, setUser] = useState(null);
    }
}

الأخطاء الشائعة مع useState

الخطأ الأكثر شيوعاً هو التغيير المباشر للكائنات والمصفوفات بدلاً من إنشاء مراجع جديدة. المطورون معتادون على الأسلوب القابل للتغيير من المكونات الفئوية، حيث كان this.state.user.name = ‘اسم جديد’ يعمل (على الرغم من أنه لم يكن موصى به أيضاً). في المكونات الوظيفية، يتم تجاهل هذا التغيير ببساطة: لا يرى React تغييراً في المرجع ولا يعيد عرض المكون.

  • تغيير الكائن « user.name = ‘جديد’ بدلاً من setUser({...user, name: ‘جديد’}).
  • إغلاق قديم « استخدام قيمة قديمة في دالة الضبط دون الشكل الوظيفي.
  • إعادة عرض زائدة « استدعاء دالة الضبط بنفس القيمة (لا يزال React 18 يقوم بإعادة عرض للأنواع البدائية).
  • إعادة تعيين الحالة « تحديث غير مقصود لخاصية المفتاح (key) لمكون، مما يؤدي إلى إعادة تركيبه.

تحدث مشكلة الإغلاق القديم عندما يلتقط استدعاء خلفي مُمرر إلى useEffect أو معالج حدث قيمة حالة قديمة من الإغلاق في وقت إنشاء الاستدعاء الخلفي. الحل هو استخدام الشكل الوظيفي لدالة الضبط أو تضمين القيم المطلوبة في مصفوفة تبعيات useEffect. وفقاً لوثائق React « الأسئلة الشائعة عن الخطافات (2025)، الإغلاقات القديمة هي ثاني أكثر سبب شيوعاً للأخطاء في الخطافات بعد مصفوفات التبعيات غير الصحيحة.

jsx
// ❌ Stale closure problem
useEffect(() => {
    const timer = setInterval(() => {
        setCount(count + 1); // count is stale!
    }, 1000);
    return () => clearInterval(timer);
}, []);

// ✅ Fixed with functional update
useEffect(() => {
    const timer = setInterval(() => {
        setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
}, []);

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

هل يمكن استخدام useState للكائنات المتداخلة المعقدة؟

نعم، ولكن مع بعض الحذر. للكائنات المتداخلة بعمق، يتطلب كل مستوى نسخاً أثناء التحديث: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). إذا كان لديك كائنات بثلاثة مستويات تداخل أو أكثر، فكر في استخدام Immer (مكتبة للتحديثات غير القابلة للتغيير) أو قسم الحالة إلى عدة استدعاءات useState لمستويات مختلفة.

هل useState غير متزامن أم متزامن؟

useState غير متزامن بمعنى أن استدعاء دالة الضبط لا يحدث القيمة فوراً. يضع React التحديث في طابور وينفذه في إعادة العرض التالية. بعد setCount(newValue)، لا يزال متغير count في الدالة الحالية يحتوي على القيمة القديمة. ستكون القيمة الجديدة متاحة فقط عند استدعاء المكون التالي. آلية التجميع تضمن تجميع الاستدعاءات المتعددة في إعادة عرض واحدة.

ماذا يحدث إذا استدعيت useState خارج المكون؟

سيطلق React خطأ استدعاء خطاف غير صالح. يمكن استدعاء الخطافات فقط داخل المكونات الوظيفية لـ React أو الخطافات المخصصة (الدوال التي تبدأ أسماؤها بـ use). هذا القيد مدمج في تنفيذ الخطافات: فهي تستخدم شجرة الألياف (fiber tree) للمكون لتخزين الحالة، وخارج المكون، هذه الشجرة غير متاحة.

متى تستخدم useState ومتى تستخدم useReducer؟

useState مناسب للحالات المستقلة البسيطة (عدادات، حقول إدخال، علامات). useReducer أفضل عندما تكون الحالة كائناً معقداً بعدة حقول، أو يعتمد منطق التحديث على نوع الإجراء، أو تتطلب الحالة التالية تحويلاً معقداً. قاعدة عملية: إذا كان لديك أكثر من ثلاثة حقول حالة مترابطة، استخدم useReducer.

لماذا لا يحدث useState القيمة فوراً؟

يتم ذلك لأسباب أداء. إذا كان useState يحدث الحالة بشكل متزامن، كل استدعاء لدالة الضبط سيطلق إعادة عرض فورية، مما يؤدي إلى إعادة رسم متعددة داخل معالج حدث واحد. التجميع في دفعات، حيث يجمع React التحديثات وينفذ إعادة عرض واحدة، هو تحسين تم تقديمه في React 16 وتحسن بشكل ملحوظ في React 18 مع التجميع التلقائي.

الخلاصة

  • useState « خطاف React أساسي لإدارة الحالة المحلية في المكونات الوظيفية، يعيد [state, setter].
  • الثبات « لا يمكن تغيير الحالة مباشرة؛ مرر دائماً قيمة جديدة أو استخدم الشكل الوظيفي لدالة الضبط.
  • التهيئة البطيئة « للحسابات الأولية المكلفة، مرر دالة: useState(() => compute()).
  • دالة ضبط وظيفية « setState(prev => prev + 1) تضمن الصحة مع التحديثات المجمعة.
  • التجميع في دفعات « يجمع React استدعاءات دالة الضبط المتعددة في إعادة عرض واحدة للتحسين.
  • قواعد الخطافات « استدعِ useState فقط في المستوى الأعلى من المكون، ليس في الشروط أو الحلقات.
  • أنواع البيانات « للكائنات والمصفوفات، أنشئ دائماً مرجعاً جديداً عند التحديث.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا