React بدون ES6

من موسوعة حسوب
مراجعة 23:38، 3 نوفمبر 2020 بواسطة محمد-بغات (نقاش | مساهمات) (تحديث)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

نُعرِّف عادةً مُكوّنات React كأصناف JavaScript مُجرَّدة:

class Greeting extends React.Component {
  render() {
    return <h1>أهلًا {this.props.name}</h1>;
  }
}

إن لم تكن تستخدم ES6 بعد، فبإمكانك استخدام الوحدة create-react-class بدلًا من ذلك:

var createReactClass = require('create-react-class');
var Greeting = createReactClass({
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});

تُشبِه واجهة برمجة التطبيقات لأصناف ES6 الصنف createReactClass()‎ مع بعض الاستثناءات.

تعريف الخاصيات الافتراضية

تُعرَّف الخاصيّات الافتراضيّة defaultProps في أصناف ودوال ES6 كخاصيّة ضمن المُكوّن نفسه:

class Greeting extends React.Component {
  // ...
}

Greeting.defaultProps = {
  name: 'Mary'
};

أمّا باستخدام createReactClass()‎ فتحتاج لتعريف الدالة getDefaultProps()‎ كدالة ضمن الكائن المُمرَّر:

var Greeting = createReactClass({
  getDefaultProps: function() {
    return {
      name: 'Mary'
    };
  },

  // ...

});

تعيين الحالة المبدئية

في أصناف ES6 تستطيع تعريف الحالة المبدئية عن طريق تعيين this.state  في الدالة البانية:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
  }
  // ...
}

يجب عليك مع الدالة createReactClass()‎ تزويدها بتابع getInitialState منفصل والذي يُعيد الحالة المبدئية:

var Counter = createReactClass({
  getInitialState: function() {
    return {count: this.props.initialCount};
  },
  // ...
});

الربط التلقائي

تتبع التوابع في مكوّنات React المُعرَّفة كأصناف ES6 نفس القواعد في أصناف ES6 الاعتيادية. يعني هذا أنّها لا تربط this بنسخة الكائن، بل يجب عليك أن تستخدم بشكل صريح التابع ‎.bind(this)‎ في الدالة البانية:

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'مرحبًا'};
    // هذا السطر هام
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    alert(this.state.message);
  }

  render() {
	// بما أن this.handleClick مربوط، فنستطيع استخدامه كمعالج للأحداث
    return (
      <button onClick={this.handleClick}>
        قل مرحبًا
      </button>
    );
  }
}

لا يكون هذا ضروريًّا مع createReactClass()‎ لأنّها تربط كل التوابع بشكلٍ تلقائي:

var SayHello = createReactClass({
  getInitialState: function() {
    return {message: 'مرحبًا'};
  },

  handleClick: function() {
    alert(this.state.message);
  },

  render: function() {
    return (
      <button onClick={this.handleClick}>
        قل مرحبًا
      </button>
    );
  }
});

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

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'مرحبًا'};
  }
  // تحذير: هذه الصياغة تجريبية
  // استخدام السهم هنا يربط التابع
  handleClick = () => {
    alert(this.state.message);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        مرحبًا
      </button>
    );
  }
}

انتبه إلى أنّ هذه الصياغة تجريبية وبالتالي قد تتغير أو لا تبقى موجودة أصلًا.

إن كنت تفضّل البقاء بأمان فلديك بعض الخيارات:

  • ربط التوابع في الدالة البانية.
  • استخدام الدوال السهمية، مثل ‎onClick={(e) => this.handleClick(e)}‎.
  • الاستمرار في استخدام createReactClass.

المخاليط (Mixins)

المخاليط هي الأصناف التي تحتوي على دوال متاحة من أجل استخدامها من قبل أصناف أخرى دون أن تكون هذه المخاليط أصنافًا آباء للأصناف التي تحتاجها.

ملاحظة: أُطلِقت ES6 بدون أي دعم للمخاليط، ولذلك لا يوجد دعم لها عندما تستخدم React مع أصناف ES6.

وجدنا أيضًا العديد من المشاكل عند استخدام المخاليط ولا نفضّل استخدامها في الشيفرات الجديدة.

يُوجَد هذا القسم فقط للتوثيق.

قد تتشارك بعض المُكوِّنات المختلفة كثيرًا ببعض الوظائف. يُدعى هذا أحيانًا بالاهتمامات المشتركة (cross-cutting concerns). يُتيح لك createReactClass أن تستخدم نظام المخاليط القديم لأجل ذلك.

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

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};

var createReactClass = require('create-react-class');

var TickTock = createReactClass({
  mixins: [SetIntervalMixin], // استخدام المخلوط
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // استدعاء تابع على المخلوط
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React قيد التشغيل منذ {this.state.seconds} ثانية.
      </p>
    );
  }
});

ReactDOM.render(
  <TickTock />,
  document.getElementById('example')
);

إذا كان المُكوّن يستخدم مخاليط متعددة تُعرِّف نفس توابع دورة الحياة (أي مثلًا تريد كل هذه المخاليط إيقاف التابع setInterval()‎ عند تدمير المُكوّن)، فسنضمن استدعاء كافة توابع دورة الحياة. تعمل التوابع المُعرَّفة في المخاليط بنفس الترتيب الذي أوردنا فيه هذه المخاليط متبوعةً باستدعاء التابع على المُكوّن.

انظر أيضًا

 مصادر