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

مكوّنات الأصناف في React: الحالة ودورة الحياة والتحويل

مكوّن الصنف صنف JavaScript يرث React.Component ويُرجع JSX من تابع render. تعلّم this.props وthis.state وsetState، وربط معالجات الأحداث، وتوابع دورة الحياة، وPureComponent، وكيف تحوّل صنفًا إلى مكوّن دالة.

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

مكوّن الصنف صنف JavaScript يرث React.Component ويُرجع JSX من تابع render(). يقرأ props من this.props، ويحتفظ بالحالة في this.state، ويحدّثها بـ this.setState(). حلّت مكوّنات الدوال مع الخطافات محلها في الكود الجديد، لكن الأصناف ما زالت مدعومة بالكامل، وتظهر في مشاريع قديمة كثيرة، وهي الطريقة الوحيدة لكتابة حدود أخطاء.

يحتفظ كل عدّاد بحالته الخاصة. أضف <Counter label="Plums" /> ثالثًا فيبدأ من 0 أيضًا.

بنية مكوّن الصنف

import { Component } from 'react';

class Welcome extends Component {
    static defaultProps = { name: 'stranger' };

    constructor(props) {
        super(props); // required before using this
        this.state = { visits: 1 };
    }

    render() {
        return <h1>Hello, {this.props.name}. Visit #{this.state.visits}</h1>;
    }
}
  • يرث الصنف Component (أو React.Component مع import React from 'react').
  • render() مطلوب. ويجب أن يكون نقيًا، مثل جسم مكوّن الدالة: يقرأ this.props وthis.state، ويُرجع JSX.
  • تحمل this.props الـ props. وهي للقراءة فقط.
  • يمكن ضبط الحالة في constructor (استدعِ super(props) أولًا) أو، وهو الأشيع اليوم، كحقل صنف: state = { visits: 1 };.
  • ما زالت static defaultProps تعمل للأصناف في React 19 (لم تُحذف إلا من مكوّنات الدوال).

this.setState يدمج، ويمكنه أخذ دالة تحديث

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

يضيف "+3 with objects" واحدًا، لأن الاستدعاءات الثلاثة كلها تقرأ this.state.likes نفسها. ويضيف "+3 with updaters" ثلاثة. ويحتفظ "Move to Paris" بـ name وlikes (الدمج) لكنه يفقد zip، لأن الدمج بعمق مستوى واحد. اكتب address: { ...this.state.address, city: 'Paris' } لتحتفظ به. ويعمل الوسيط الثاني الاختياري لـ setState بعد التحديث، وتُظهر وحدة التحكم العنوان الجديد هناك.

ربط معالجات الأحداث

التابع الممرر على شكل onClick={this.handleClick} يُستدعى لاحقًا كدالة عادية، دون كائنه، فتكون this بداخله undefined.

يسجّل الزر الأول خطأ TypeError عن قراءة setState من undefined. ويعمل الثاني، لأن الدالة السهمية في حقل صنف تلتقط this عند إنشاء النسخة. والإصلاح الأقدم، الذي ما زال شائعًا في الكود القديم، يربط في المُنشئ:

constructor(props) {
    super(props);
    this.state = { on: false };
    this.handleClick = this.handleClick.bind(this);
}

وتعمل أيضًا دالة سهمية مضمّنة، onClick={() => this.handleClick()}.

توابع دورة الحياة

تستجيب الأصناف للتركيب والتحديث والإزالة عبر توابع بأسماء ثابتة. وأكثر ما ستراه منها:

  • componentDidMount(): بعد أن يكون العرض الأول في DOM. ابدأ المؤقتات والاشتراكات والطلبات.
  • componentDidUpdate(prevProps, prevState): بعد كل تحديث. قارن بالقيم السابقة قبل أداء أي عمل، وإلا دخلت في حلقة.
  • componentWillUnmount(): قبل الإزالة. ألغِ ما بدأه componentDidMount.
  • shouldComponentUpdate(nextProps, nextState): أرجع false لتتخطى عرضًا.

في صفحة دورة حياة المكوّن القائمة الكاملة، وترتيب تشغيلها، ومكوّن يسجّل كل واحد منها.

تحويل صنف إلى مكوّن دالة

إليك صنفًا يستخدم توابع دورة الحياة الثلاثة الشائعة. ينبض كل ثانية، ويسجّل عندما تتغير الـ prop المسماة label، ويوقف مؤقته عند إزالته.

والمكوّن نفسه كدالة. يصبح كل تابع دورة حياة جزءًا من تأثير، ويجلس الإعداد والتنظيف المترابطان أحدهما بجانب الآخر بدلًا من أن يكونا في تابعين.

يعدّ المؤقتان بالطريقة نفسها ويسجّلان مع كل تغيير للتسمية. وتسجّل نسخة الدالة أيضًا مرة عند التركيب، لأن التأثير يعمل بعد العرض الأول كذلك. خطوات أي تحويل:

  1. يصبح this.props.x prop مفككة، { x }.
  2. يصبح كل مفتاح في this.state استدعاء useState خاصًا به. وتذكّر أن دالة الضبط تستبدل ولا تدمج.
  3. تصبح التوابع دوال عادية داخل المكوّن. لا حاجة إلى الربط.
  4. تصبح componentDidMount وcomponentDidUpdate وcomponentWillUnmount استدعاءات useEffect، مجمّعة بحسب ما تفعله لا بحسب وقت تشغيلها.
  5. يصبح createRef هو useRef، ويصبح static contextType مع this.context هو useContext أو use.

اترك حدود الأخطاء أصنافًا؛ فلا مقابل لها في الدوال.

PureComponent

يُعرض مكوّن الصنف العادي في كل مرة يُعرض فيها أبوه. أما PureComponent فيقارن أولًا props والحالة الجديدة بالسابقة، بعمق مستوى واحد، ويتخطى العرض عندما لا يتغير شيء. وهو نظير الأصناف لـ React.memo.

انقر الزر: لا يُسجَّل إلا PlainLabel rendered، لأن PureLabel يرى text نفسها. مرّر text={'hello ' + clicks} إلى كليهما فيُعرضان مع كل نقرة.

المقارنة سطحية، فالـ prop التي تكون كائنًا أو دالة جديدة في كل عرض للأب (style={{ color: 'red' }} وonClick={() => ...}) تُبطلها. وهو الفخ نفسه الذي مع React.memo.

ما حذفته React 19 من الأصناف

إذا كنت تصون كود أصناف قديمًا، فبعض الأنماط لم تعد تعمل في React 19:

  • مراجع النصوص (ref="input" مع this.refs.input). استخدم createRef() أو دالة مرجع.
  • السياق القديم (contextTypes وchildContextTypes وgetChildContext). استخدم createContext مع static contextType.
  • propTypes تُتجاهل. استخدم TypeScript أو فحوصك الخاصة.
  • findDOMNode زال. ضع مرجعًا على عنصر DOM بدلًا منه.

والتوابع القديمة componentWillMount وcomponentWillReceiveProps وcomponentWillUpdate قديمة هي الأخرى. ما زالت تعمل، بالأسماء القديمة وبأسماء UNSAFE_ (UNSAFE_componentWillMount وما شابه)، لكنها مُهملة ويحذّر منها StrictMode؛ انقل كودها إلى componentDidMount أو componentDidUpdate أو getDerivedStateFromProps.

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

هل أُهملت مكوّنات الأصناف في React؟

لا. ما زالت مدعومة في React 19 وستستمر في العمل، لكن وثائق React توصي بمكوّنات الدوال مع الخطافات للكود الجديد. وما زلت تحتاج إلى صنف لحدود الأخطاء.

ما الفرق بين مكوّنات الأصناف ومكوّنات الدوال؟

يحتفظ مكوّن الصنف بالحالة في this.state، ويحدّثها بـ this.setState، ويستجيب لدورة الحياة عبر توابع مسماة. أما مكوّن الدالة فيستخدم الخطافات (useState وuseEffect) للمهام نفسها، ولا يحتاج إلى this، وهو أقصر.

هل يحدّث setState الحالة فورًا؟

لا. يجدول this.setState تحديثًا وتعرض React لاحقًا، فتظل this.state تحمل القيمة القديمة مباشرة بعد الاستدعاء. مرّر دالة، this.setState((state) => ...)، عندما تعتمد القيمة الجديدة على القديمة، أو اقرأ النتيجة في دالة الاستدعاء التي هي الوسيط الثاني أو في componentDidUpdate.

لماذا تكون this قيمتها undefined في معالج الحدث الخاص بي؟

تابع الصنف الممرر على شكل onClick={this.handleClick} يُستدعى دون كائنه، فتكون this هي undefined. عرّف المعالج كدالة سهمية في حقل صنف (handleClick = () => { ... }) أو اربطه في المُنشئ.

ما هو PureComponent؟

مكوّن Component يتخطى العرض عندما تكون props والحالة متساوية سطحيًا مع السابقة. وهو نسخة الأصناف من React.memo.

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

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

ابدأ الآن