دليل شامل للمبتدئين: بناء تطبيقات React حديثة خطوة بخطوة (مع استخدام Hooks)

دقائق القراءة: 28

هل أنت متحمس للبدء في تعلم مكتبة React؟ لقد وصلت إلى المكان الصحيح! سيأخذك هذا الدليل خطوة بخطوة عبر كل ما تحتاج لمعرفته عند الشروع في رحلتك مع React. سنقوم بإعداد بيئة العمل، وشرح ‘كيف ولماذا’ وراء المفاهيم الأساسية، ثم سنبني مشروعًا صغيرًا يجلب البيانات من واجهة برمجة تطبيقات (API) لنرى كل شيء عمليًا.

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

المتطلبات الأساسية

لا تحتاج إلى معرفة مسبقة بـ React قبل قراءة هذا الدليل. ولكن هناك بعض الأمور التي ستحتاج إلى الإلمام بها لتحقيق أقصى استفادة من هذا الدليل:

أساسيات JavaScript

React هي مكتبة JavaScript، لذا من المنطقي أن تكون على دراية بـ JavaScript قبل تعلم React، أليس كذلك؟ لا تقلق، لن تحتاج إلى معرفة JavaScript بشكل كامل، بل يكفي أن تكون على دراية بالأساسيات:

  • المتغيرات (Variables)، الدوال (functions)، وأنواع البيانات (data types).
  • المصفوفات (Arrays) والكائنات (Objects).
  • صيغة ES6 (مثل استخدام let و const، دوال السهم Arrow Functions، التفكيك Destructuring Assignment، الفئات classes، الاستيراد والتصدير importing/exporting، إلخ).
  • كيفية استخدام JavaScript للتلاعب بنموذج كائن المستند (DOM).

أساسيات HTML

في React، نستخدم ما يسمى JSX لإنشاء بنية HTML لصفحات الويب الخاصة بنا. سنشرح JSX بالتفصيل لاحقًا، ولكن في الوقت الحالي، تأكد من أن لديك أساسًا جيدًا عندما يتعلق الأمر بـ HTML:

  • كيفية بناء HTML (كيفية تداخل العناصر وما إلى ذلك).
  • سمات HTML (مثل id، class، onclick وما إلى ذلك).

بيئة التطوير

أول شيء سنفعله هو إعداد بيئة تطوير. إذا كنت قد قمت بالفعل بإعداد Node.js وتثبيت Visual Studio Code (أو بيئة التطوير المتكاملة IDE المفضلة لديك)، يمكنك الانتقال إلى القسم التالي.

Node.js

توجه إلى الموقع الرسمي لـ Node.js وقم بتنزيل الحزمة المناسبة لنظام التشغيل الخاص بك (Mac/Windows، إلخ). عند اكتمال التثبيت، افتح الطرفية (terminal) واكتب هذا الأمر:

node -v

يجب أن يظهر هذا الأمر إصدار Node الذي قمت بتثبيته للتو:

إصدار Node.js في الطرفية

هذا يعني أن الأمر node يعمل وأن Node قد تم تثبيته بنجاح! إذا رأيت أي أخطاء، حاول إعادة تثبيت Node من الحزمة التي قمت بتنزيلها وأعد محاولة الأمر مرة أخرى.

Visual Studio Code

Visual Studio Code هو بيئة تطوير متكاملة (IDE) مفتوحة المصدر وشائعة تعمل بشكل جيد لتطوير الواجهة الأمامية (frontend). هناك العديد من البدائل الأخرى التي يمكنك تجربتها، اختر ما تفضله وقم بتنزيله. في الوقت الحالي، سنستخدم VS Code. اتبع خطوات التثبيت، وستكون جاهزًا للانطلاق. قم بتشغيل Visual Studio Code. هذا يكفي لإعداد بيئة التطوير في الوقت الحالي. هناك أشياء أخرى مفيدة يمكنك تثبيتها (مثل إضافات VS Code extensions)، ولكننا لسنا بحاجة إليها الآن، فنحن هنا لنتعلم React!

إنشاء تطبيق React

الخطوة التالية هي إنشاء مشروع React. لحسن حظنا، جعل فريق Facebook الأمر بسيطًا للغاية. كل ما علينا فعله هو تشغيل أمر واحد في الطرفية:

npx create-react-app my-app

ينشئ هذا الأمر مشروعًا لنا باسم “my-app” ويقوم بإعداد كل شيء تلقائيًا. رائع جدًا! افتح الطرفية في الدليل الذي تريد إنشاء تطبيقك فيه، على سبيل المثال، مجلد “projects“، وقم بتشغيل الأمر. دع الطرفية تقوم بعملها، وبعد فترة، سيكتمل الأمر ويعرض لك بعض الأوامر:

إخراج أمر create-react-app في الطرفية

لاحظ أن إخراج create-react-app قد أخبرنا بما نحتاج إلى فعله لبدء التطبيق. قم بتشغيل الأوامر في الطرفية:

cd my-app
yarn start

سيؤدي هذا إلى بدء خادم تطوير وفتح متصفح ويب لك:

تطبيق React يعمل في المتصفح

لقد قمت للتو بإعداد أول تطبيق React لك! إذا كنت ترغب في معرفة المزيد حول ما يحدث، يمكنك البحث عن مشروع create-react-app مفتوح المصدر على GitHub.

استكشاف بنية تطبيق React

افتح Visual Studio Code (أو أي بيئة تطوير متكاملة IDE قمت بتثبيتها) واختر File > Open… وحدد مجلد “my-app” الذي تم إنشاؤه لنا للتو باستخدام create-react-app. سيؤدي هذا إلى فتح تطبيق React الجديد الخاص بنا في بيئة التطوير المتكاملة، حتى نتمكن من كتابة بعض الأكواد! يجب أن ترى بنية المشروع على اليمين:

هيكل مجلدات مشروع React

لا تقلق كثيرًا بشأن الكثير من هذه الملفات، فهي في الغالب أكواد وإعدادات جاهزة (boilerplate code and config) لن نعدل عليها كثيرًا في هذا الدرس. ومع ذلك، بما أنك مطور فضولي، دعنا نلقي نظرة على شجرة المشروع ونرى ما لدينا:

مجلد Node Modules

هذا هو المكان الذي توضع فيه الحزم (packages) التي نقوم بتثبيتها من خلال مدير حزم Node (NPM). إذا لم تكن على دراية بـ NPM، فهو مكان رائع حيث يمكننا مشاركة الأكواد (عادةً مفتوحة المصدر) التي يمكن للمطورين الآخرين استخدامها بدلاً من كتابة أكوادهم الخاصة. بدلاً من استخدام وسوم script tags كما نفعل في HTML التقليدي، نقوم بتثبيت هذه الوحدات (modules) كجزء من التطبيق. ثم نستخدم عبارة import statement للوصول إلى الكود من تلك الوحدة. سنرى هذا عمليًا لاحقًا.

المجلد Public

هذا هو المكان الذي توضع فيه الأكواد المجمعة (bundled code) الخاصة بنا. عندما نكون مستعدين لنشر تطبيقنا، نقوم بتشغيل سكربت بناء (build script) وتذهب الملفات النهائية إلى هنا. ستكون هذه عادةً ملفات HTML و JavaScript و CSS الخاصة بنا. هذا هو المجلد الذي نرفعه إلى خادم ويب في مكان ما، حتى يتمكن المستخدمون من رؤية تطبيقنا عبر عنوان URL.

ملف Index.html

ملف index.html هو نقطة الدخول (entry point)، أو أول شيء يقوم متصفح الويب بتحميله عندما يتصفح المستخدم عنوان URL الذي يستضيف تطبيقنا. إذا نظرنا إلى الملف، فهو مجرد ملف HTML عادي يحتوي على أشياء HTML عادية نأمل أن تكون على دراية بها. إذا نظرنا إلى وسم body، فسنجده فارغًا. سيقوم React بتحويل كود React الخاص بنا ديناميكيًا إلى HTML وتحميله هنا، في وسم div ذي المعرف “root“. بعد أن أوضحنا ذلك، دعنا ننتقل إلى الأجزاء الشيقة، وهي الكود.

مكوننا الأول في React

افتح ملف App.js من شجرة المشروع. هذا هو المكون الرئيسي (Main component) في تطبيقنا. إنه أول مكون يتم عرضه. إنه “العنصر الأهم” بين المكونات. أول شيء سنفعله في هذا المكون الرئيسي هو حذف كل شيء، وبناء مكوننا الخاص من الصفر، لفهم أفضل لما يحدث. الآن بعد أن أصبح لدينا لوح أبيض نظيف للعمل عليه، سنبدأ باستيراد react. هذا يجلب مكتبة React إلى نطاق العمل ويمنحنا الوصول إلى جميع الميزات الرائعة:

import React from "react";

بعد ذلك، سنقوم بتعريف دالة. سنستخدم دوال السهم ES6 arrow functions هنا. هذا هو ما يعنيه “المكون” (component) تقريبًا، دالة تحتوي على بعض المنطق والعلامات (markup). سنقوم أيضًا بتصدير هذه الدالة (export) حتى نتمكن من استخدامها في أماكن أخرى:

const App = () => { }
export default App;

داخل دالتنا، نريد كتابة return(). هذا هو ما يتم إرجاعه من هذا المكون، ويحتوي على العلامات الخاصة بنا التي يتم تحويلها وعرضها كـ HTML. أخيرًا، دعنا نضيف وسم <div> مع وسم عنوان <h1>. يبدو مكوننا النهائي كما يلي:

import React from "react";

const App = () => {
  return (
    

Hello React World

This is our first React App - isn't it marvellous?!

); } export default App;

الآن ربما تفكر، “واو! HTML في دالة؟ ما هذا الجنون؟” على الرغم من أنه يبدو كـ HTML، إلا أنه في الواقع شيء يسمى JSX (JavaScript XML). هذا يسمح لنا أساسًا بخلط JavaScript و HTML معًا. قد يبدو هذا غريبًا بعض الشيء. لقد تعلمنا في الأصل تطوير الواجهة الأمامية (front end) بفصل HTML و JavaScript (وحتى CSS). ومع ذلك، تطور JavaScript وطريقة تصميم التطبيقات، والحفاظ على كل شيء معًا في نفس “المكون” (component) يجعل صيانة الكود وإعادة استخدامه أسهل. دعنا نرى هذا عمليًا. افتح الطرفية وقم بتشغيل:

npm start

يجب أن يفتح هذا المتصفح ويجب أن ترى التطبيق يعمل. تهانينا! لقد أنشأت للتو أول مكون لك!

فهم JSX: دمج JavaScript و HTML

ربما لديك بعض علامات الاستفهام حول مفهوم JSX. دعنا نلقي نظرة أعمق على هذا.

return (
  

Hello React World

This is our first React App - isn't it marvellous?!

);

هذا يبدو كـ HTML، لكنه ليس كذلك. هذا هو JSX! على الرغم من أنه يبدو كـ HTML عادي، ما يحدث خلف الكواليس هو أن React يقوم بإنشاء شجرة العناصر (element tree)، باستخدام هذه الصيغة:

React.createElement(component, props, ...children)
  • component: عنصر HTML الذي ترغب في إنشائه، أي h1، div، إلخ.
  • props: أي خصائص (props) ترغب في تمريرها إلى هذا المكون (سنتحدث عن props لاحقًا).
  • children: مصفوفة من عناصر HTML المتداخلة داخل هذا العنصر.

لذا، يمكن كتابة نفس المكون الذي أنشأناه للتو على النحو التالي:

const App = () => {
  return (
    React.createElement(
      "div",
      null,
      React.createElement("h1", null, "Hello React World"),
      React.createElement("h2", null, "This is our first React App - isn't it marvellous?!")
    )
  );
}

والذي يبدو معقدًا بعض الشيء. إذا تتبعت الكود بعناية، يمكنك أن ترى أننا نقوم بإنشاء عنصر div، والذي لا يحتوي على أي خصائص (props) (يشار إلى ذلك بتمرير null كوسيط ثانٍ). أخيرًا، نقوم بإنشاء عنصرين آخرين باستخدام صيغة createElement، وهما عنصرا H1 و H2. إذا كنت تعمل مع JavaScript لفترة من الوقت، فقد لاحظت أن هذا يشبه document.createElement. وهذا صحيح! إنها مكتبة JavaScript بعد كل شيء! هذه هي ميزة JSX في React، حيث تتيح لنا كتابة صيغة تشبه HTML، دون الحاجة إلى تعقيدات React.createElement(). في العالم الحقيقي، يستخدم مطورو React بشكل شبه حصري JSX لكتابة أكوادهم. لا، لم يكن هذا القسم مضيعة للوقت، فمن الجيد دائمًا فهم ما يحدث تحت الغطاء. المعرفة قوة!

جعل المكونات ديناميكية باستخدام JSX

لقد رأينا JSX، وتجاوزنا خوفنا منه (نأمل ذلك). ولكن ما الفائدة؟ لماذا نستخدم JSX، بينما يمكننا ببساطة استخدام HTML؟ إنهما يبدوان متشابهين، أليس كذلك؟ سؤال جيد يا صديقي! حسنًا، إذا تذكرنا ما يرمز إليه JSX، فهو JavaScript XML. هذا يعني أنه يمكننا استخدام JavaScript لجعل الأشياء ديناميكية. كان مثالنا السابق يبدو كما يلي:

const App = () => {
  return (
    

Hello React World

This is our first React App - isn't it marvellous?!

); }

الآن لنفترض أننا نريد جعل نصنا أكثر ديناميكية. أولاً، دعنا نضيف متغيرًا (variable) للاحتفاظ برسالتنا: const message = "This is my first variable rendered in JSX!". الآن لإضافة JavaScript إلى هذا، نستخدم الأقواس المتعرجة (curly braces):

const App = () => {
  const message = "This is my first variable rendered in JSX!";
  return (
    

Hello React World

{message}

); }

إذا قمت بتشغيل هذا في المتصفح، ستلاحظ ظهور نص متغير message. قم بتغيير نص متغير message إلى شيء آخر وشاهد السحر يحدث. نستخدم الأقواس المتعرجة لإخبار المترجم (compiler) “نفذ هذا الكود كـ JavaScript“. إذا لم نستخدم الأقواس المتعرجة، فلن يتم تنفيذ متغير message كـ JavaScript، وبدلاً من ذلك، سيظهر النص “message” على الشاشة. جرب هذا وشاهد!

التعامل مع الأحداث (Events)

يمكن اتباع نفس النهج عند التعامل مع الأحداث. عند استخدام JSX، يمنحنا React الوصول إلى مستمعي الأحداث (event listeners) التي قد تكون مألوفًا لك بالفعل: onClick، onPress، onSubmit وما إلى ذلك. لنفترض أننا نريد عرض تنبيه (alert) عند النقر على الرسالة. أولاً، نضيف خاصية onClick إلى وسم h2 الخاص بنا. تقبل خاصية onClick دالة (بعبارة أخرى، نمرر دالة كوسيط). ستستدعي هذه الدالة التنبيه على النحو التالي:

const App = () => {
  const message = "This is my first variable rendered in JSX!";
  return (
    

Hello React World

alert("you clicked the message!")}>{message}

); }

لاحظ كيف نستخدم دالة السهم (arrow function) هنا لإنشاء دالة مضمنة (inline function) موجزة وجميلة. مرة أخرى، لاحظ كيف وضعنا هذا الكود داخل الأقواس المتعرجة (curly braces)، لضمان تنفيذ الدالة كـ JavaScript.

استدعاء الدوال (Functions)

لقد نظرنا إلى الدوال المضمنة في المثال الأخير. بما أن JSX هو JavaScript، يمكننا إنشاء الدوال والإشارة إليها خارج كتلة الإرجاع (return block). يمكن أن يبدو مثالنا الأخير على النحو التالي:

const App = () => {
  const message = "This is my first variable rendered in JSX!";
  const handleClick = () => {
    alert("you clicked the message!");
  }
  return (
    

Hello React World

{message}

); }

لاحظ كيف أنشأنا دالة تسمى handleClick والتي تعرض الرسالة. بدلاً من استخدام دالة مضمنة، نشير إلى هذه الدالة في خاصية onClick الخاصة بنا. جرب هذا وشاهد ما يحدث. هذه مجرد أمثلة قليلة حول كيفية استخدام JavaScript لجعل الأشياء ديناميكية، ونأمل أن يوضح لك قوة JSX. سنتعمق في فهمنا لاحقًا بينما نبني مثالًا، لذا لا تقلق إذا لم تكن بعض الأشياء منطقية بعد!

كيف يتم عرض المكونات في React؟

آمل أن أكون قد أوضحت بعض الأسئلة التي قد تكون لديك حول JSX. الشيء التالي الذي قد تتساءل عنه هو: كيف يتم عرض المكون (component)؟ أين؟ متى؟ دعنا نبدأ من البداية. إذا عدت إلى بنية ملفاتنا، فلدينا ملف index.js. هذا هو أول ملف يتم تشغيله (غالبًا ما نسميه “نقطة الدخول” Entry Point). هذا عادة ما يكون بالاتفاق، يمكنك تغيير نقطة الدخول إذا أردت، ولكن في الوقت الحالي سنتركه كما هو. إذا تعمقنا في الملف، ستلاحظ أن لدينا هذا السطر:

ReactDOM.render(
  <App />,
  document.getElementById("root"));

لاحظ أن لدينا document.getElementById("root")، أخيرًا بعض أكواد JavaScript ذات المظهر الطبيعي! يقوم هذا بالحصول على العنصر الجذر (root element) من نموذج كائن المستند (DOM) باستخدام JavaScript العادي، ويعرض مكون App الخاص بنا بداخله. يتم استيراد مكون App الخاص بنا على النحو التالي:

import App from "./App"

تذكر أننا قمنا بتصدير مكون App الخاص بنا في ملف App.js. هذا يسمح للملفات/المكونات الأخرى باستيراد واستخدام مكون App الخاص بنا. إذن من أين يأتي العنصر الجذر؟ حسنًا، هل تتذكر ملف index.html الخاص بنا في المجلد العام (public folder)؟ هذا الملف index.html هو أول ملف HTML يتم تحميله عند تحميل الموقع. بداخله لدينا وسم div بمعرف ID يسمى “root“، وهو فارغ. هذا هو المكان الذي يقوم فيه React بتحميل مكوناتنا. دعنا نلقي نظرة على هذا في أدوات المطور (dev tools). افتح Chrome (أو أي متصفح تستخدمه) وافحص أدوات المطور. سترى في مكان ما في الشجرة وسم div بمعرف id="root"، بالإضافة إلى HTML المعروض من مكون App الخاص بنا. رائع جدًا!

عنصر div ذو المعرف root في أدوات المطور

ملخص سريع

قبل المتابعة، دعنا نلخص بسرعة ما تعلمناه حتى الآن:

  • لدينا ملف index.html، وهو هيكل تطبيق الويب الخاص بنا.
  • عند بدء التطبيق، يتم تحميل index.html، ويقوم باستيراد مكون App الخاص بنا.
  • يتم تحويل JSX في مكون App إلى HTML، والذي يتم عرضه بعد ذلك في ملف index.html ضمن وسم div الجذر (root div).

بناء قائمة جهات اتصال تفاعلية

الآن بعد أن أصبح لدينا فهم أساسي لـ React، وفهم أفضل لكيفية ترابط الأشياء، دعنا نبني تطبيقًا مثالًا باستخدام ما تعلمناه حتى الآن. سنتعلم أيضًا بعض ميزات React الشائعة التي ستساعدك على المضي قدمًا في طريقك لتعلم React. هيا بنا! ستعرض قائمة جهات الاتصال الخاصة بنا عددًا من جهات الاتصال، بما في ذلك الاسم والبريد الإلكتروني والعمر والصورة الرمزية (أو صورة الملف الشخصي). سنبني هذا تدريجيًا، وفي النهاية سنجلب البيانات من واجهة برمجة تطبيقات (API). يا له من أمر مثير!

مثال على قائمة جهات الاتصال في React

تضمين الأنماط (Styles)

بما أن هذا درس تعليمي عن React، فسنركز على العمليات الداخلية لـ React ولن نقلق بشأن إنشاء أنماط جميلة. في مجلد المصدر (source folder) الخاص بك، أنشئ ملفًا جديدًا باسم styles.css والصق الكود التالي فيه:

.contact-card {
  display: flex;
  padding: 10px;
  color: #ffffff;
  background-color: rgb(42, 84, 104);
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  box-shadow: 10px 10px 25px -16px rgba(0, 0, 0, 0.75);
  border-radius: 10px;
  max-width: 500px;
  max-height: 125px;
  margin-bottom: 10px;
}

.contact-card p {
  margin-left: 10px;
  margin-top: 0;
}

button {
  margin-left: 10px;
  margin-bottom: 10px;
}

بعد ذلك، انتقل إلى ملف App.js وقم باستيراد ورقة الأنماط (stylesheet) على النحو التالي:

import "./styles.css";

إنشاء بطاقة جهة الاتصال (Contact Card)

بينما نحن لا نزال في ملف App.js، دعنا نضيف JSX الأساسي لإنشاء تخطيط بطاقة جهة الاتصال. قم بإزالة كل شيء من عبارة return وأضف ما يلي:

<div className="contact-card">
  <img src="https://via.placeholder.com/150" alt="profile"/>
  <div className="user-details">
    <p>Name: Jenny Han</p>
    <p>Email: Jenny.Han@notreal.com</p>
    <p>Age: 25</p>
  </div>
</div>

كل ما نفعله هنا هو إنشاء وسم div “لتغليف” تفاصيل بطاقة جهة الاتصال، وإضافة صورة (ستستخدم الصورة مكانًا مؤقتًا من الويب في الوقت الحالي)، وإضافة عدد قليل من وسوم p للاحتفاظ بالتفاصيل التي نحتاجها في بطاقة جهة الاتصال. أخيرًا، نضيف بعض فئات CSS المأخوذة من ملف styles.css؛ ملاحظة: للإشارة إلى فئات CSS، نحتاج إلى استخدام الكلمة المفتاحية className. هذا لأننا نكتب JSX، وكلمة “class” هي كلمة محجوزة في JavaScript. إليك ما لدينا حتى الآن في ملف App.js الخاص بنا:

import React from "react";
import "./styles.css";

const App = () => {
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile"/>
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
}

إذا قمت بتشغيل هذا في المتصفح، يجب أن ترى شيئًا مشابهًا لما يلي:

نموذج بطاقة جهة اتصال في React

جعل بطاقة جهة الاتصال قابلة لإعادة الاستخدام

لدينا الآن بطاقة جهة اتصال! ومع ذلك، فهي ليست قابلة لإعادة الاستخدام بشكل كبير. نعلم أننا سنحتاج إلى إعادة استخدام هذا الكود إذا أردنا عرض أكثر من بطاقة واحدة، لذا من المنطقي تقسيم هذا إلى مكون خاص به. ملاحظة: لتسهيل المتابعة، سأضع جميع المكونات التي ننشئها في ملف App.js. في العالم الحقيقي، سيكون من الأفضل تقسيم هذه المكونات المختلفة إلى ملفات خاصة بها، واستيرادها وتصديرها (import/export) عند الاقتضاء. أسفل دالة App مباشرة، أنشئ دالة جديدة تسمى ContactCard، وانسخ JSX من App إلى ContactCard على النحو التالي:

const ContactCard = () => {
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile"/>
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
};

مرة أخرى، المكون (component) في React هو مجرد دالة تُرجع بعض JSX. الآن بعد أن نقلنا JSX الخاص بنا إلى ContactCard، يمكننا استخدام هذا المكون داخل مكون App الرئيسي الخاص بنا:

const App = () => {
  return (
    <>
      <ContactCard />
    </>
  );
}

نستخدم مكوناتنا الخاصة مثل أي وسم HTML/JSX قديم. نضع فقط اسم مكوننا بين أقواس الزاوية. يجب أن يبدو ملف App.js الخاص بنا كما يلي:

// App.js
import React from "react";
import "./styles.css";

const App = () => {
  return (
    <>
      <ContactCard />
    </>
  );
};

const ContactCard = () => {
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile"/>
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
};

الآن إذا قمت بتشغيل هذا في المتصفح، ستبدو الأمور كما كانت من قبل، وهذا ما نريده. لدينا الآن مكون ContactCard يمكننا استخدامه عدة مرات كما نشاء:

const App = () => {
  return (
    <>
      <ContactCard />
      <ContactCard />
      <ContactCard />
    </>
  );
};

قم بتحديث مكون App لتضمين مكونين إضافيين من ContactCard. سيعرض المثال أعلاه 3 بطاقات اتصال في المتصفح. اذهب وتحقق من ذلك! فكر في هذا كـ “طابع” على الصفحة. كل مكون ContactCard نضيفه هو “طابع” آخر ويعرض نفس العلامات (markup) على الصفحة.

فهم الحالة (State) باستخدام Hook: useState

إذا كنت قد بدأت بالفعل في تعلم React، فربما تكون قد سمعت بمصطلح “الحالة” (state). الحالة أمر مهم جدًا في React. فما هي؟ الحالة هي في الأساس كائن (object) يمثل جزءًا من التطبيق يمكن أن يتغير، وتتفاعل معه واجهة المستخدم (UI). يمكن أن تكون الحالة أي شيء: كائنات، قيم منطقية (booleans)، مصفوفات (arrays)، سلاسل نصية (strings)، أو أعداد صحيحة (integers).

دعنا نأخذ مثالاً. بعض الأشخاص الذين يظهرون في قائمة جهات الاتصال لدينا خجولون ولا يريدون عرض أعمارهم حتى يتم النقر على زر. يمكننا تخزين ما إذا كان يجب عرض العمر أم لا في الحالة (state) باستخدام خطاف useState داخل المكون. والذي يبدو كما يلي:

const [showAge, setShowAge] = useState(false);

“ما الذي يحدث هنا بحق الجحيم؟” دعني أشرح. يمنحنا كائن useState متغيرًا (variable) بالقيمة الحالية (current value)، ودالة (function) تتيح لنا تغيير تلك القيمة. عندما نستدعي useState، يمكننا تحديد قيمة أولية (initial value) (في هذه الحالة، false). نستخدم تعيين التفكيك (destructuring assignment) على خطاف useState للحصول على هذه القيم. لا داعي للقلق بشأن تعيين التفكيك الآن، فقط تذكر أن المتغير الأول يتيح لنا الوصول إلى قيمة الحالة (state value)، والثاني يتيح لنا تغييرها. قم بإضافة مقتطف الكود أعلاه إلى مكون ContactCard على النحو التالي:

const ContactCard = () => {
  const [showAge, setShowAge] = useState(false);
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile"/>
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        <p>Age: 25</p>
      </div>
    </div>
  );
};

الآن لدينا كائن حالة (state object)، كيف نستخدمه؟ حسنًا، يمكننا الإشارة إلى متغير showAge مثل أي متغير آخر. في هذه الحالة، نريد فقط عرض العمر إذا كانت قيمة متغير showAge هي true. يمكننا القيام بذلك باستخدام عامل التشغيل الثلاثي (ternary operator):

{showAge === true ? <p>Age: 25</p> : null}

يقرأ هذا المثال على النحو التالي: إذا كان متغير showAge صحيحًا (true)، فاعرض العمر، وإلا، فلا تعرض شيئًا (null). امض قدمًا وأضف هذا إلى مكون ContactCard، على النحو التالي:

const ContactCard = () => {
  const [showAge, setShowAge] = useState(false);
  return (
    <div className="contact-card">
      <img src="https://via.placeholder.com/150" alt="profile"/>
      <div className="user-details">
        <p>Name: Jenny Han</p>
        <p>Email: Jenny.Han@notreal.com</p>
        {showAge === true ? <p>Age: 25</p> : null}
      </div>
    </div>
  );
};

الآن، إذا قمت بتشغيل التطبيق في المتصفح، سترى أن العمر يختفي، وذلك لأن متغير showAge الخاص بنا قد تم تهيئته بقيمة false. إذا قمنا بتهيئة متغير showAge الخاص بنا بقيمة true:

const [showAge, setShowAge] = useState(true);

سيظهر العمر على بطاقة جهة الاتصال. رائع! على الرغم من ذلك، ليس هذا مثاليًا، لا نريد تغيير الكود في كل مرة نريد فيها إظهار العمر على بطاقة جهة الاتصال! قبل أن ننظر في كيفية تغيير متغير showAge الخاص بنا ديناميكيًا، دعنا نرتب الكود قليلاً. امض قدمًا واستبدل هذا السطر:

{showAge === true ? <p>Age: 25</p> : null}

بـ:

{showAge && <p>Age: 25</p>}

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

تحديث الحالة (State)

حسنًا، نعود إلى تحديث الحالة (state). إذا تذكرنا، فإن خطاف useState() يمنحنا دالة لتحديث الحالة. دعنا نربط هذا بزر، والذي، عند النقر عليه، سيقوم بتبديل إظهار العمر على بطاقة جهة الاتصال. يمكننا القيام بذلك بما يلي:

<button onClick={ () => setShowAge(!showAge)}> Toggle Age </button>

ما يفعله هذا هو استدعاء دالة setShowAge (التي نحصل عليها من خطاف useState) لتغيير قيمة showAge إلى عكس ما هي عليه حاليًا. عندما تتغير الحالة (state)، سيقوم React بإعادة عرض المكون (re-render the component)، وبما أن قيمة showAge هي true، فسيتم عرض العمر. إذا نقر المستخدم على الزر مرة أخرى، فسيؤدي ذلك إلى تعيين showAge إلى false، وسيقوم React بإعادة عرض المكون، وسيتم إخفاء العمر:

زر تبديل العمر في بطاقة جهة الاتصال

شاهد زر التبديل الرائع الخاص بنا وهو يعمل! نصيحة: كلما تغيرت حالة المكون (component's state)، سيقوم React بإعادة عرض المكون بالحالة الجديدة. لاحظ أنه على الرغم من أن لدينا 3 مكونات ContactCard يتم عرضها، فعند النقر على الزر، يظهر العمر لبطاقة واحدة فقط، وليس لجميع البطاقات. هذا لأن الحالة (state) تخص المكون الفردي. بعبارة أخرى، كل مكون ContactCard يتم عرضه هو نسخة (copy)، وله حالته/بياناته الخاصة.

تقديم Props: تمرير البيانات بين المكونات

الآن لدينا مكون ContactCard جديد ورائع نقوم بإعادة استخدامه عدة مرات. على الرغم من ذلك، فهو ليس قابلًا لإعادة الاستخدام حقًا، لأن الاسم والبريد الإلكتروني والعمر والصورة الرمزية (avatar) هي نفسها لكل من مكوناتنا. يا للهول! يمكننا جعل هذه البيانات أكثر ديناميكية باستخدام ما يسمى “الخصائص” (props). بما أنك بدأت للتو في تعلم React، يمكنك التفكير في Props على أنها بيانات يتم تمريرها إلى مكون (component)، يمكن للمكون بعد ذلك استخدامها. على سبيل المثال، يمكننا تمرير الصورة الرمزية (avatar) والبريد الإلكتروني (email) والاسم (name) والعمر (age) كـ props إلى مكون Contact Card الخاص بنا على النحو التالي:

<ContactCard avatar="https://via.placeholder.com/150" name="Jenny Han" email="jenny.han@notreal.com" age={25} />

كما ترى، نقوم بتعريف خاصية (prop) بإعطائها اسمًا. على سبيل المثال، name واستخدام علامة المساواة لتعيين قيمة لتلك الخاصية، على سبيل المثال، Jenny Han. يمكن أن يكون لدينا العديد من الخصائص (props كما نريد، ويمكننا تسمية هذه الخصائص بأي اسم نريده، لذا فهي مرنة جدًا. يمكن أن تحتوي Props على أنواع مختلفة من البيانات، أي سلاسل نصية (strings)، أرقام (numbers)، قيم منطقية (booleans)، كائنات (objects)، مصفوفات (arrays) وما إلى ذلك. ملاحظة: يجب تعريف Props باستخدام نص مقتبس (مثل name="Jenny Han") أو داخل أقواس متعرجة (مثل age={25}). إذا تركنا الأقواس المتعرجة لأي شيء بخلاف السلاسل النصية، تبدأ الأمور في الانهيار (age=25).

امض قدمًا واستبدل مكونات ContactCard الحالية داخل مكون App الخاص بنا بما يلي:

<ContactCard avatar="https://via.placeholder.com/150" name="Jenny Han" email="jenny.han@notreal.com" age={25} />
<ContactCard avatar="https://via.placeholder.com/150" name="Jason Long" email="jason.long@notreal.com" age={45} />
<ContactCard avatar="https://via.placeholder.com/150" name="Peter Pan" email="peter.pan@neverland.com" age={100} />

كل ما نفعله هنا هو تمرير البيانات التي يحتاجها المكون إلى كل مكون كـ props. لاحظ كيف تختلف البيانات لكل مكون.

استخدام Props داخل المكونات

لقد أرسلنا مجموعة من الخصائص (props) إلى مكون ContactCard، لذا دعنا نخبر ContactCard بكيفية استخدامها. حتى الآن، لا تقبل دالة ContactCard أي معلمات (parameters). React، بكونه شيئًا سحريًا، يضع جميع خصائصنا تلقائيًا في كائن props object رائع، يتم تمريره إلى المكون:

const ContactCard = props => {
  //...other code
};

لاحظ متغير props. هذا كائن يحتوي على الخصائص التي عرفناها سابقًا. يمكننا الوصول إلى خصائصنا المعرفة باستخدام ترميز النقطة (dot notation) على النحو التالي:

const ContactCard = props => {
  console.log(props.avatar);
  console.log(props.name);
  console.log(props.email);
  console.log(props.age);
  //...other code
};

أخيرًا، نريد استبدال القيم الثابتة (hardcoded values) في JSX الخاص بنا، بالقيم التي نتلقاها من الخصائص (props):

return (
  <div className="contact-card">
    <img src={props.avatar} alt="profile"/>
    <div className="user-details">
      <p>Name: {props.name}</p>
      <p>Email: {props.email}</p>
      <button onClick={() => setShowAge(!showAge)}>Toggle Age</button>
      {showAge && <p>Age: {props.age}</p>}
    </div>
  </div>
);

لاحظ كيف قمنا بتعيين مصدر الصورة (image source) باستخدام أي قيمة تلقيناها من props. فعلنا الشيء نفسه بالنسبة لـ name و email و age. لاحظ أيضًا كيف نغلف هذا الكود في أقواس متعرجة (curly braces)، بحيث يتم تنفيذه كـ JavaScript. يبدو ملف App.js النهائي الخاص بنا كما يلي:

// App.js
const App = () => {
  return (
    <>
      <ContactCard avatar="https://via.placeholder.com/150" name="Jenny Han" email="jenny.han@notreal.com" age={25} />
      <ContactCard avatar="https://via.placeholder.com/150" name="Jason Long" email="jason.long@notreal.com" age={45} />
      <ContactCard avatar="https://via.placeholder.com/150" name="Peter Pan" email="peter.pan@neverland.com" age={100} />
    </>
  );
};

const ContactCard = props => {
  const [showAge, setShowAge] = useState(false);
  return (
    <div className="contact-card">
      <img src={props.avatar} alt="profile"/>
      <div className="user-details">
        <p>Name: {props.name}</p>
        <p>Email: {props.email}</p>
        <button onClick={() => setShowAge(!showAge)}>Toggle Age</button>
        {showAge && <p>Age: {props.age}</p>}
      </div>
    </div>
  );
};

إذا قمت بتشغيل هذا في المتصفح، يجب أن ترى شيئًا مشابهًا لهذا:

قائمة جهات اتصال ديناميكية في React

مرحى! يعمل مكوننا بنفس الطريقة من قبل، ولكنه الآن أكثر ديناميكية. يمكننا إعادة استخدام نفس ContactCard ولكن بتمرير بيانات مختلفة، مع الحفاظ على نفس التخطيط والأنماط وكائنات الحالة (state objects).

عرض المكونات من قائمة (Array)

قائمة جهات الاتصال لدينا تتقدم بشكل جيد، ولدينا كود مصمم جيدًا وقابل لإعادة الاستخدام، لذا حان الوقت لتركه وشأنه، أليس كذلك؟ خطأ! دعنا نخطو خطوة أخرى. في تطبيق حقيقي، تأتي البيانات عادةً في شكل مصفوفة (array) من البيانات، على سبيل المثال، بعد استدعاء واجهة برمجة تطبيقات (API call). دعنا نتظاهر بأننا قمنا باستدعاء API لاسترداد بعض المستخدمين من قاعدة بيانات وتلقينا البيانات التالية:

const contacts = [
  { name: "Jenny Han", email: "jenny.han@notreal.com", age: 25 },
  { name: "Jason Long", email: "jason.long@notreal.com", age: 45 },
  { name: "Peter Pan", email: "peter.pan@neverland.com", age: 100 }
];

الصق هذا في مكون App() في الجزء العلوي من الدالة. سيلاحظ ذوو العين الثاقبة منكم كيف أن هذه البيانات مشابهة لما لدينا بالفعل. ولكن كيف نحول هذه البيانات إلى مكونات ContactCard؟ حسنًا، هل تتذكر كل تلك الأيام التي قضيتها في تعلم كيفية التكرار على مصفوفة باستخدام .map()؟ الآن هو اليوم الذي نطبق فيه ذلك عمليًا! لعرض قائمة من المكونات، نقوم بما يلي:

  1. التكرار على المصفوفة باستخدام .map().
  2. لكل عنصر في المصفوفة، إنشاء مكون ContactCard جديد.
  3. تمرير البيانات من كل كائن في المصفوفة إلى مكون ContactCard كـ props.

دعنا نرى كيف يعمل هذا. في مكون App() الخاص بنا، استبدل عبارة return بهذا:

return (
  <>
    {contacts.map(contact => (
      <ContactCard avatar="https://via.placeholder.com/150" name={contact.name} email={contact.email} age={contact.age} />
    ))}
  </>
);

كما ترى، نقوم بعملية map على المصفوفة. لكل كائن في المصفوفة، نريد إنشاء مكون ContactCard جديد. بالنسبة للخصائص (props)، نريد أخذ name و email و age من الكائن الحالي الذي تعمل عليه دالة map. بعبارة أخرى، من متغير contact. ملاحظة: لقد تركت خاصية “avatar” كما هي في الوقت الحالي، حيث إنها نفسها في جميع الحالات، ستتغير لاحقًا في هذا الدرس التعليمي. وهذا كل شيء! يبدو ملف App.js الخاص بنا كما يلي:

//App.js
const App = () => {
  const contacts = [
    { name: "Jenny Han", email: "jenny.han@notreal.com", age: 25 },
    { name: "Jason Long", email: "jason.long@notreal.com", age: 45 },
    { name: "Peter Pan", email: "peter.pan@neverland.com", age: 100 },
    { name: "Amy McDonald", email: "amy@email.com", age: 33 }
  ];

  return (
    <>
      {contacts.map(contact => (
        <ContactCard avatar="https://via.placeholder.com/150" name={contact.name} email={contact.email} age={contact.age} />
      ))}
    </>
  );
};

قم بتشغيل هذا في المتصفح ويجب أن تبدو الأمور كما هي. لم نغير مكون ContactCard الخاص بنا، بل غيرنا فقط مصدر البيانات. الشيء الرائع في هذا هو أنه إذا أضفت صفًا آخر إلى مصفوفة contacts، فسيتم عرض المكون الإضافي تلقائيًا، ولن تضطر إلى فعل أي شيء آخر! جرب هذا بنفسك وشاهد.

جلب البيانات من واجهة برمجة التطبيقات (API)

لدينا الآن تطبيق React App ذو مظهر جيد. إنه ديناميكي والأمور تسير على ما يرام. وهذا مكان جيد للبدء به بما أننا بدأنا للتو في تعلم React! ولكن هناك بعض التعديلات التي نحتاج إلى إجرائها. في تطبيق حقيقي، سيتم جلب البيانات من واجهة برمجة تطبيقات (API). في الجزء التالي من هذا الدرس التعليمي، سنحصل على جهات اتصال حقيقية (عندما أقول جهات اتصال حقيقية، أعني جهات اتصال وهمية، أنت تعرف ما أعنيه) من واجهة برمجة تطبيقات حقيقية: https://randomuser.me/. لا تتردد في تصفح الموقع والاطلاع على الاستجابة التي سنحصل عليها، فهذا هو المكان الذي سنحصل منه على بياناتنا لملء مكوناتنا.

أولاً، دعنا ننشئ متغير حالة (state variable) للاحتفاظ بالبيانات التي نحصل عليها من واجهة برمجة التطبيقات (API). تذكر أن الحالة (state) جيدة للاحتفاظ بالبيانات التي يمكن أن تتغير. قائمة جهات الاتصال لدينا يمكن أن تتغير بالتأكيد! في ملف App.js، قم بإزالة مصفوفة contacts وأضف ما يلي:

const [contacts, setContacts] = useState([]);

ما نفعله هنا هو إنشاء كائن حالة (state object)، وتهيئته إلى مصفوفة فارغة. عندما نجري استدعاء واجهة برمجة التطبيقات (API call)، سنقوم بتحديث الحالة (state) لتضمين قائمة من جهات الاتصال. بما أننا سمينا كائن الحالة هذا contacts، فإن منطق العرض الخاص بنا داخل JSX سيبحث عن هذه المصفوفة بدلاً من ذلك (على عكس مصفوفة contacts القديمة التي حذفناها للتو).

بعد ذلك، دعنا نجلب البيانات من واجهة برمجة التطبيقات (API). سنستخدم واجهة Fetch API القياسية. في الوقت الحالي، سنقوم بتسجيل البيانات في وحدة التحكم (console). أضف ما يلي أسفل كائن الحالة الذي أنشأناه للتو:

fetch("https://randomuser.me/api/?results=3")
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });

كل ما نفعله هنا هو:

  • إجراء طلب GET إلى واجهة randomuser API، لطلب ثلاث نتائج.
  • تحويل الاستجابة إلى تنسيق JSON.
  • تسجيل JSON في وحدة التحكم (console).

إذا قمت بتشغيل هذا في المتصفح، ستلاحظ أن مكونات ContactCard لم تعد تُعرض، وهذا أمر طبيعي، لم نقم بحفظ أي بيانات جديدة في الحالة (state) بعد، ومتغير الحالة الخاص بنا فارغ حاليًا. إذا نظرت إلى وحدة التحكم (console) (في أدوات مطوري المتصفح)، ستلاحظ أن كائن الاستجابة (response object) قد تم تسجيله. والذي سيبدو شيئًا كهذا:

كائن الاستجابة من واجهة برمجة التطبيقات

سترى أن لدينا مصفوفة results، والتي تحتوي على 3 كائنات. يحتوي كل من هذه الكائنات على تفاصيل مستخدم (أو “جهة اتصال” في حالتنا). هذا مشابه لمصفوفة contacts التي أنشأناها يدويًا في القسم السابق، مجرد مصفوفة مليئة بالكائنات. دعنا نحدث JSX لمكون App الخاص بنا لجلب البيانات من هذا الكائن. قم بتحديث JSX على النحو التالي:

return (
  <>
    {contacts.map(contact => (
      <ContactCard avatar={contact.picture.large} name={contact.name.first + " " + contact.name.last} email={contact.email} age={contact.dob.age} />
    ))}
  </>
);

يعمل هذا بشكل مشابه لما كان لدينا من قبل:

  • نحن نكرر عبر متغير contacts (الذي هو حاليًا مصفوفة فارغة).
  • عندما نقوم في النهاية بحفظ الاستجابة في الحالة (state) (الخطوة التالية)، فإننا نبحث في كل كائن في المصفوفة عن الأشياء المناسبة التي نحتاجها: في هذه الحالة، كائنات picture و name و email و dob.

بعد ذلك، نريد تخزين مصفوفة results في الحالة (state)، بحيث يمكن لـ JSX الخاص بنا التكرار عليها (باستخدام دالة map() التي رأيناها سابقًا) وعرض بعض بطاقات ContactCards الجميلة. داخل دالة fetch الخاصة بنا، أضف استدعاء setContacts(data.results) على النحو التالي:

fetch("https://randomuser.me/api/?results=3")
  .then(response => response.json())
  .then(data => {
    console.log(data);
    setContacts(data.results);
  });

يبدو مكون App الخاص بنا الآن كما يلي:

//App.js
const App = () => {
  const [contacts, setContacts] = useState([]);
  fetch("https://randomuser.me/api/?results=3")
    .then(response => response.json())
    .then(data => {
      console.log(data);
      setContacts(data.results);
    });

  return (
    <>
      {contacts.map(contact => (
        <ContactCard avatar={contact.picture.large} name={contact.name.first + " " + contact.name.last} email={contact.email} age={contact.dob.age} />
      ))}
    </>
  );
};

إذا قمت بحفظ هذا، وتشغيله في المتصفح، سترى شيئًا كهذا:

تطبيق React يقوم باستدعاءات متكررة لواجهة برمجة التطبيقات

قد تفكر، “ما الذي يحدث؟ كل شيء معطل!” لا داعي للذعر بعد. (إذا كنت تستخدم جهازًا أبطأ أو شعرت بالتوتر، يمكنك التعليق على سطر setContacts(data.results) داخل دالة fetch في الوقت الحالي). ما يحدث هنا هو أننا عالقون في حلقة مفرغة بعض الشيء:

  1. نقوم باستدعاء fetch ونحصل على بعض البيانات.
  2. ثم نحفظ هذه البيانات في الحالة (state).
  3. تذكر أن React يقوم بإعادة عرض المكون (re-render) عندما تتغير الحالة (state).
  4. عندما يعاد عرض المكون، يحدث استدعاء fetch api call مرة أخرى، ويقوم بتعيين الحالة (state).
  5. بما أن الحالة (state) تم تحديثها، يعاد عرض المكون مرة أخرى.
  6. بعد إعادة عرض المكون، يتم استدعاء fetch مرة أخرى…
  7. لقد فهمت الفكرة.

إذن كيف نوقف هذا؟ لا داعي لحذف كل شيء والبدء من جديد. يمكننا إصلاح هذا باستخدام خطاف React Hook آخر مدمج، وهو useEffect.

التعريف بـ Hook: useEffect

خطاف useEffect هو خطاف خاص يقوم بتشغيل دالة. بشكل افتراضي، يتم تشغيل خطاف useEffect في كل عملية إعادة عرض. ومع ذلك، يمكننا تكوينه ليعمل فقط في ظل ظروف معينة، على سبيل المثال، عندما يتم تحميل المكون (component mounts)، أو إذا تغير متغير. يبدو خطاف useEffect كما يلي:

useEffect( () => {
  // code to run
});

سيتم تشغيل هذا في كل مرة. إذا أردنا تحديد “التشغيل مرة واحدة فقط”، فإننا نمرر مصفوفة فارغة كوسيط ثانٍ على النحو التالي:

useEffect( () => {
  // code to run
},[]); //<-- لاحظ المصفوفة الفارغة

يسمى هذا “مصفوفة التبعيات” (dependency array). عندما تكون مصفوفة التبعيات فارغة، فهذا يعني أن دالة useEffect ستعمل فقط عندما يتم تحميل المكون لأول مرة. بالنسبة لعمليات إعادة العرض الإضافية، يتم تخطي دالة useEffect. هذا مكان مثالي لوضع استدعاء واجهة برمجة التطبيقات (API call) الخاص بنا، حيث نريد فقط الحصول على البيانات مرة واحدة، عندما يتم تحميل المكون. امض قدمًا وضع دالة useEffect() في مكون App الخاص بنا، وانقل استدعاء fetch API إلى دالة useEffect. يبدو مكون App الخاص بنا الآن كما يلي:

//App.js
const App = () => {
  const [contacts, setContacts] = useState([]);

  useEffect(() => {
    fetch("https://randomuser.me/api/?results=3")
      .then(response => response.json())
      .then(data => {
        setContacts(data.results);
      });
  }, []);

  return (
    <>
      {contacts.map(contact => (
        <ContactCard avatar={contact.picture.large} name={contact.name.first + " " + contact.name.last} email={contact.email} age={contact.dob.age} />
      ))}
    </>
  );
};

الآن، إذا قمت بتشغيل الكود في متصفحك، يجب أن ترى 3 بطاقات اتصال تظهر! قم بتحديث الصفحة لترى قائمة عشوائية أخرى من جهات الاتصال:

قائمة جهات اتصال ديناميكية يتم جلبها من API

الخلاصة التقنية

تهانينا! لقد أكملت للتو أول تطبيق حقيقي لك باستخدام React، ووضعت الأساس للانتقال إلى مواضيع أكثر تقدمًا. لقد تعلمت كيفية إعداد بيئة التطوير، وإنشاء المكونات، وفهم قوة JSX في جعل واجهة المستخدم ديناميكية. كما اكتشفت كيفية إدارة الحالة (State) باستخدام خطاف useState، وتمرير البيانات بين المكونات باستخدام Props، وعرض القوائم بكفاءة. الأهم من ذلك، لقد أتقنت استخدام خطاف useEffect لجلب البيانات من واجهات برمجة التطبيقات (APIs) بشكل فعال وتجنب الحلقات اللانهائية. هذه المفاهيم هي اللبنات الأساسية لأي تطبيق React حديث، وستمكنك من بناء واجهات مستخدم معقدة وتفاعلية.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *