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

لماذا يحتاج مطوّر React إلى فهم JavaScript الحديثة؟
الاسم المعياري للغة JavaScript هو ECMAScript، وقد جاءت نسخة ES6 أو ECMAScript 2015 بميزات غيرت طريقة كتابة الشيفرة بشكل كبير. وعلى الرغم من أنه يمكن بناء تطبيقات React بأسلوب أقدم، فإن الاعتماد على الصياغات الحديثة يجعل الشيفرة أوضح وأسهل في الصيانة وأقل عرضة للأخطاء.
عند قراءة مشاريع React الحقيقية، ستلاحظ استخداماً متكرراً لمفاهيم مثل let وconst وtemplate literals وdestructuring وspread operator. لذلك، فإن التمكن من هذه الأساسيات ليس رفاهية، بل شرط عملي للكتابة بثقة وكفاءة.

استخدام let وconst بدلاً من var
في الإصدارات الأقدم من JavaScript، كان التصريح عن المتغيرات يتم غالباً باستخدام var. لكن مع ES6 أصبح لدينا let وconst، وهما خياران أكثر أماناً ووضوحاً.
varيعمل ضمن نطاق الدالةfunction scope.letيعمل ضمن نطاق الكتلةblock scope.constيشبهlet، لكن لا يسمح بإعادة إسناد قيمة جديدة للمتغير بعد تعريفه.
مثال على var:
var x = 10;
function someFunc() {
var y = 10;
console.log('inside someFunc', x, y);
}
وعند تنفيذ الدالة someFunc() ستكون النتيجة:
inside someFunc 10 10
لكن إذا حاولت الوصول إلى المتغير y خارج الدالة، فستحصل على الخطأ التالي:
Uncaught ReferenceError: y is not defined
مثال يوضح الفرق بين var وlet داخل حلقة for:
function letsLoop() {
for (var i = 0; i < 5; i++) {
console.log('i inside the loop:', i);
}
console.log('i outside of loop', i);
}
الناتج:
i inside the loop: 0
i inside the loop: 1
i inside the loop: 2
i inside the loop: 3
i inside the loop: 4
i outside of loop 5
أما عند استبدال var بـ let:
function letsLoop() {
for (let i = 0; i < 5; i++) {
console.log('i inside the loop:', i);
}
console.log('i outside of loop', i);
}
فستظهر رسالة خطأ عند الوصول إلى i خارج الحلقة:
i inside the loop: 0
i inside the loop: 1
i inside the loop: 2
i inside the loop: 3
i inside the loop: 4
Uncaught ReferenceError: i is not defined
مثال على const:
const name = 'freeCodeCamp';
name = 'My freeCodeCamp';
// Uncaught TypeError: Assignment to constant variable.
وعند التعامل مع الكائنات object، يمكن تعديل الخصائص الداخلية، لكن لا يمكن إعادة إسناد الكائن نفسه:
const publication = {
name: 'freeCodeCamp'
};
publication.name = 'My freeCodeCamp'; // Allowed
publication = {}; // Uncaught TypeError: Assignment to constant variable.
| الكلمة | نوع النطاق | إعادة الإسناد | الوصول قبل التعريف |
|---|---|---|---|
var |
نطاق دالة | مسموح | undefined |
let |
نطاق كتلة | مسموح | ReferenceError |
const |
نطاق كتلة | غير مسموح | ReferenceError |
عملياً، يفضَّل الالتزام بالقواعد التالية:
- تجنّب استخدام
varفي المشاريع الحديثة. - استخدم
constكلما كانت القيمة لن تتغير. - استخدم
letعندما تحتاج إلى إعادة الإسناد لاحقاً.
في مشاريع React ستجد هذا النمط واضحاً جداً، كما في المثال التالي:
const DifficultyLevels = () => {
const userDataLS = getFromLS(LS_KEY_USER_DATA);
const [userData, setUserData] = useState(
userDataLS || {
fullName: '',
age: '',
email: '',
gender: 'F',
difficultyLevel: BEGINNER
}
);
useEffect(() => {
let level = 'beginner';
if (userData.age >= 10 && userData.age <= 13) {
level = 'intermediate';
} else if (userData.age > 13) {
level = 'advanced';
}
setUserData({ ...userData, difficultyLevel: level });
}, [userData.age]);
return (
<>
<span>{userData.level}</span>
</>
);
};
الاستفادة من Template Literals
كانت عملية دمج النصوص في الماضي تعتمد على استخدام علامة +، وهي طريقة مرهقة وتزيد احتمال الوقوع في أخطاء. مع template literals أصبح من الممكن كتابة النصوص بشكل أكثر قرباً من اللغة الطبيعية.
var name = 'Tapas';
var publication = 'freeCodeCamp';
var greeting = 'Hello';
var message = greeting + ' ' + name + ', welcome to ' + publication + '.';
والصياغة الأحدث:
let name = 'Tapas';
let publication = 'freeCodeCamp';
let greeting = 'Hello';
let message = `${greeting} ${name}, welcome to ${publication}.`;
هذا الأسلوب مفيد جداً داخل مكوّنات React، خاصة عند بناء رسائل ديناميكية أو عند استخدام مكتبات مثل styled-components.
الاستيراد والتصدير عبر Modules
من أهم طرق التفكير الصحيحة في React تقسيم الواجهة إلى مكوّنات مستقلة. وكل مكوّن غالباً ما يعيش داخل ملف منفصل، ما يعني أنك ستستخدم مفهوم modules بشكل يومي عبر import وexport.
// under-construction.js
// src/components/utility
import React from "react";
const UnderConstruction = () => {
return (
<div className="column">
<p style={{ marginTop: "10px" }}>
If you are seeing this, I am probably working on it! Please give it a few days to get constructed.
</p>
</div>
);
};
export default UnderConstruction;
وفي ملف آخر:
import UnderConstruction from './components/utility/under-construction';
فهم هذا النمط يسهل عليك إعادة استخدام المكوّنات، وتنظيم المشروع، وتوسيع التطبيق لاحقاً دون فوضى.
استخدام Arrow Functions
لا يشترط استخدام arrow functions لكتابة تطبيق React، لكنها أصبحت جزءاً شائعاً من أسلوب الكتابة الحديث. وهي تجعل تعريف الدوال أكثر اختصاراً، كما تساعد في تجنب بعض الإشكالات المرتبطة بالكلمة this.
const double = (num) => {
return num * 2;
};
وتظهر فائدتها بوضوح داخل الدوال الراجعة callbacks ومع المكوّنات الوظيفية.
فهم Destructuring للكائنات والمصفوفات
يُستخدم destructuring لاستخراج القيم من الكائنات أو المصفوفات إلى متغيرات بشكل مباشر وواضح. وهذه ميزة ستراها كثيراً في تطبيقات React، خاصة مع props وstate.
مثال داخل حلقة:
for (let { name, age } of users) {
console.log(`${name} is ${age} years old!`);
}
مثال مع قيمة راجعة من دالة:
const getUser = () => {
return {
name: 'Alex',
address: '15th Park Avenue',
age: 43
};
};
const { name, age } = getUser();
console.log(name, age); // Alex 43
مثال ضمن معاملات الدالة:
function logDetails({ name, age }) {
console.log(`${name} is ${age} year(s) old!`);
}
ومثال على array destructuring:
let emojis = ['🔥', '⏲️', '🏆', '🍉'];
let [fire, clock, , watermelon] = emojis;
console.log(fire, clock, watermelon); // 🔥 ⏲️ 🍉
الفرق بين Spread Operator وRest Parameter
تساعدك صياغة spread على تفكيك عناصر المصفوفة أو خصائص الكائن، بينما يساعدك rest على تجميع عدد من القيم في بنية واحدة. وتكمن أهمية spread operator في React عند تحديث الحالة state دون تعديل الكائن الأصلي مباشرة.
const clone_some_object = { ...some_object };
هذا الأسلوب شائع جداً عند نسخ الكائنات والمصفوفات وإنشاء نسخة جديدة تساعد React على إعادة التصيير re-render بشكل صحيح.
التعامل مع Classes في JavaScript
رغم أن المكوّنات الوظيفية أصبحت الأكثر شيوعاً اليوم، فإن فهم classes يظل مفيداً، لأنك قد تصادفها في مشاريع قديمة أو أثناء قراءة شيفرات تعليمية.
class Employee {
constructor(name) {
this.name = name;
}
greeting() {
return `Hello, ${this.name}`;
}
}
let emp = new Employee("Tapas");
emp.greeting(); // "Hello, Tapas"
ويمكن أيضاً بناء مكوّن React باستخدام class:
class Greeting extends React.Component {
render() {
return <span>Hello World!</span>;
}
}
ومن المفيد كذلك معرفة مفاهيم إضافية مثل for-of وasync-await وternary operator لأنها تظهر باستمرار في المشاريع الحقيقية.
معمارية المكوّنات في React
أحد أهم أسباب نجاح React هو أسلوبها القائم على تقسيم الواجهة إلى مكوّنات صغيرة مستقلة. فبدلاً من وضع كل شيء داخل ملف واحد، يتم تقسيم التطبيق إلى وحدات منطقية، تؤدي كل وحدة منها وظيفة واضحة ومحددة.

عندما تعتمد على ملف ضخم واحد، قد تواجه مشكلات كثيرة، منها:
- ارتفاع احتمال تعارضات الدمج
merge conflictsعند عمل أكثر من مطور على نفس الملف. - ضعف إعادة استخدام الشيفرة وزيادة التكرار.
- تباطؤ التطوير لأن الفريق لا يعمل بكفاءة على أجزاء مستقلة.
- صعوبة اختبار أجزاء التطبيق بشكل منفصل.
- تحوّل أي تعديل بسيط إلى مخاطرة تمس التطبيق بأكمله.
في المقابل، يساعدك تقسيم التطبيق إلى مكوّنات على بناء مشروع أكثر قابلية للصيانة، وأسهل في الاختبار، وأوضح في التعاون الجماعي.
كيف تتخيل التطبيق كمجموعة مكوّنات؟
لنفترض أنك تطور تطبيقاً تعليمياً يعرض نتائج الطلاب حسب الصفوف الدراسية. الواجهة تحتوي على:
- شريط تنقل علوي يضم الشعار واسم التطبيق.
- تقسيم واضح للنتائج بحسب الصف.
- عرض أفضل ثلاثة طلاب في كل صف.
- رابط
view allلعرض جميع النتائج. - حقل بحث للوصول إلى نتيجة أي طالب عبر الاسم.

عند تحليل هذه الواجهة، يمكن تقسيمها إلى المكوّنات التالية:
- مكوّن جذري باسم
App. - مكوّن
Navلشريط التنقل العلوي. - مكوّن
Resultsلمحتوى الصفحة الرئيسي. - مكوّن
Searchللبحث. - مكوّن
Scoresلاحتواء كل النتائج. - مكوّن
Scoreلكل مجموعة نتائج خاصة بصف معين. - مكوّن
ScoreHeadingلعنوان مثلGrade 1. - مكوّن
ScoreListلجدول النتائج.

فهم تركيب المكوّنات Component Composition
بعد تحديد المكوّنات، ننتقل إلى كيفية تركيبها معاً. فالمكوّنات ليست جزرًا معزولة، بل ترتبط ببعضها من خلال البيانات والعلاقات الهرمية.
- المكوّن
Appيحتوي علىNavوResults. - المكوّن
Resultsيحتوي علىSearchوScores. - المكوّن
Scoresقد يحتوي على عدة مكوّنات من النوعScore. - كل
Scoreيحتوي علىScoreHeadingوScoreList.


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

ما هو NPM؟
NPM هو مدير الحزم الخاص بمنصة Node.js. يتيح لك اكتشاف الحزم البرمجية، وتثبيتها، وإدارة الاعتماديات dependencies، ونشر مكتباتك الخاصة عند الحاجة.
وفي عالم React، ستتعامل مع NPM باستمرار لتثبيت أدوات ومكتبات تضيف وظائف ليست متاحة بشكل افتراضي.
لماذا تحتاج إليه أثناء تطوير تطبيقات React؟
مكتبة React ممتازة في بناء الواجهات، لكنها لا توفر كل شيء بشكل مدمج. لذلك قد تحتاج إلى مكتبات خارجية مثل:
- إدارة الحالة المتقدمة عبر
Redux. - التنقل بين الصفحات باستخدام مكتبات التوجيه
routing. - إظهار الرسوم البيانية
charts. - معالجة النصوص والتواريخ والمهام المساعدة.
- أدوات الاختبار والبناء والتحسين.
وجود هذه الحزم على NPM يجعل تطوير التطبيقات أسرع وأكثر احترافية، لأنك لا تبدأ من الصفر في كل مرة.
عقلية المصدر المفتوح Open Source
أحياناً قد لا تجد الحزمة المناسبة لاحتياجك، أو قد تجد حزمة موجودة لكنها لا تلائم مشروعك تماماً. في هذه الحالة، لديك خياران عمليان:
- تطوير الحل بنفسك على هيئة مكوّن أو مكتبة، ثم اختباره ونشره كحزمة على
NPM. - المساهمة في مشروع مفتوح المصدر قائم وتحسينه بما يخدمك ويخدم المجتمع التقني.
هذه العقلية مهمة جداً لمطوّر React، لأنها لا تجعله مجرد مستخدم للأدوات، بل مشاركاً في تطوير المنظومة نفسها. كما أن الإسهام في المشاريع المفتوحة المصدر يساعد على بناء خبرة عملية وسمعة مهنية قوية.
نصائح عملية لتعلّم React بفعالية
- ابدأ أولاً بإتقان أساسيات
JavaScriptالحديثة قبل التعمق فيReact. - درّب نفسك على تقسيم أي واجهة تراها إلى مكوّنات صغيرة.
- تعلّم قراءة الشيفرة أكثر من الاكتفاء بكتابتها، لأن قراءة المشاريع الواقعية توسّع فهمك بسرعة.
- استخدم الحزم الخارجية بوعي، ولا تضف مكتبة لمجرد أنها شائعة.
- احرص على فهم سبب استخدام
propsوstateبدلاً من حفظ التعاريف فقط.
الخلاصة التقنية
React ليست مجرد مكتبة لعرض عناصر الواجهة، بل طريقة تفكير متكاملة في بناء التطبيقات. وكلما كان فهمك لـ JavaScript الحديثة أقوى، أصبح تعاملك مع المكوّنات وإدارة البيانات وتنظيم المشروع أكثر احترافية. ومن الناحية التقنية، فإن النجاح في React يعتمد على ثلاثة محاور أساسية: كتابة شيفرة حديثة وواضحة، تصميم مكوّنات صغيرة قابلة لإعادة الاستخدام، والاستفادة الذكية من منظومة NPM دون إفراط. إذا أتقنت هذه الركائز، فستمتلك أساساً متيناً للانتقال من التعلم النظري إلى بناء تطبيقات حقيقية قابلة للتوسع والصيانة.