بداية سريعة
أهلا بك في مستندات react، هذه الصفحة ستعطيك مقدمة ل ٨٠٪ من مفاهيم React التي يتم استخدامها بشكل روتيني في مشاريع React.
You will learn
- كيف تقوم بإنشاء ودمج المكوّنات.
- كيف تضيف تأثيرات على العناصر.
- كيف تقوم بعرض البيانات.
- كيف تستخدم الجمل الشرطية وتعرض عناصر القوائم.
- كيف تتجاوب مع الأحداث المختلفة وتحدث شاشة المستخدم بناءً عليها.
- كيف تشارك البيانات بين أكثر من مكوّن.
إنشاء ودمج المكوّنات
يتم صناعة تطبيقات React اعتمادا على ما يعرف بـ (المكوّنات - Components). المكوّن هو جزء مستقل من واجهة المستخدم والتي لها المنطق البرمجي والشكل الخاص بها. يمكنك تشكيل المكوّن بالحجم والشكل المناسب فيتراوح من كونه صغيرا ليمثل (زر) أو كبيرا ليمثل صفحة كاملة. المكوّنات ليست إلا دوال JavaScript والتي توفر (ترميزا مرئيا) كقيمة مرجعة من الدالة.
function MyButton() {
return (
<button>أنا زر</button>
);
}
الآن قمت ببناء مكوّن باسم MyButton
، يمكنك الآن إدخاله في مكون آخر:
export default function MyApp() {
return (
<div>
<h1>مرحبًا بكم في تطبيقي</h1>
<MyButton />
</div>
);
}
لاحظ كيف أن المكوّن <MyButton />
يبدأ بحرف (كبير) في الإنجليزية (M)، وهي طريقة مستخدمة في React للتمييز ومعرفة أن هذه الدالة تمثل مكوّن. أسماء المكوّنات في React يجب أن تبدأ دائما بحرف كبير، بينما يجب أن تكون وسوم ال html المستخدمة بحرف صغير.
خذ نظرة سريعة على النتيجة:
function MyButton() { return ( <button> أنا زر </button> ); } export default function MyApp() { return ( <div> <h1>مرحبًا بكم في تطبيقي</h1> <MyButton /> </div> ); }
عبارة export default
تحدد المكوّن الأساسي في الملف. إذا لم يكن لديك معرفة كافية عن طريقة بناء وكتابة الكود في JavaScript، فيمكنك الرجوع للمصادر التالية:
MDN
javascript.info
بناء الترميز المرئي للواجهة باستخدام JSX
طريقة بناء جمل ترميز الواجهات الذي شاهدته في الأعلى هو ما يسمى بـ JSX. استخدام الـ JSX يعتبر اختياريا، لكن معظم مشاريع React تستخدم الـ JSX لسهولة التعامل معها. كل الأدوات التي ننصح بها لبيئة التطوير تدعم الـ JSX.
تعتبر JSX أكثر صرامة من ال HTML. حيث يجب عليك إغلاق العلامات مثل <br />
. وكذلك فإن المكوّن الذي تقوم بإنشائه لا يمكن أن يرجع لك مجموعة من علامات ال JSX، بل يجب عليك إحاطتهم بأبٍ مشترك مثل: <div>...</div>
أو حتى غطاء <>...</>
الفارغ.
function AboutPage() {
return (
<>
<h1>عنوان</h1>
<p>مرحبًا جميعًا.<br />كيف حالكم?</p>
</>
);
}
إذا كان لديك الكثير من الأكواد المكتوبة بال HTML والتي ترغب في تحويلها إلى الـ JSX، فيمكنك استخدام تحويل الـ HTML لـ JSX أون لاين.
إضافة أنماط تصميمية
في React يمكنك تحديد تصنيف باستخدام className
. حيث أنها تعمل تماما كما تعمل خاصية class
في الـ HTML:
<img className="avatar" />
و بعد ذلك يمكنك كتابة قواعد الـ CSS لهذا التصنيف في ملف CSS منفصل:
/* In your CSS */
.avatar {
border-radius: 50%;
}
React لا تحدد لك كيف يجب عليك إضافة ملفات الـ CSS لملف الـ HTML.
ببساطة يمكنك إضافة وسم <link>
لملف الـ html الخاص بك.
إذا كنت تستخدم أداة بناء معينة أو إطار عمل فاستفسر عن طريقة إضافة ملفات الـ CSS لمشروعك من خلال المستندات الخاصة بالأداة.
عرض البيانات
تمكنك الـ JSX من إدخال ترميز الواجهة بداخل JavaScript، ويمكنك من خلال الأقواس المعقوفة “الخروج من ترميز الواجهة” والعودة مرة أخرى إلى سياق JavaScript حتى تتمكن من تضمين متغير من أكوادك وعرضه للمستخدم، فمثلا الكود التالي سيُظهر user.name
للمستخدم على الشاشة:
return (
<h1>
{user.name}
</h1>
);
يمكنك كذلك “الخروج إلى سياق JavaScript” من داخل خواص الـ JSX، لكن يجب عليك حينها استخدام الأقواس المعقوفة بدلا من علامات التنصيص. فمثلا className="avatar"
تقوم بتمرير "avatar"
على أنه التصنيف المستخدم في الـ CSS، ولكن src={user.imageUrl}
تقوم بقراءة قيمة متغير JavaScript التالي: user.imageUrl
ومن ثم تقوم بتمرير قيمته لتمثل خاصية الـ src
:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
يمكنك كذلك وضع تعبيرات برمجية أكثر تعقيدا بداخل أقواس الـ JSX المعقوفة، مثلا دمج النصوص:
const user = { name: 'هايدي لامار', imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg', imageSize: 90, }; export default function Profile() { return ( <> <h1>{user.name}</h1> <img className="avatar" src={user.imageUrl} alt={'Photo of ' + user.name} style={{ width: user.imageSize, height: user.imageSize }} /> </> ); }
في المثال الموضح أعلاه style={{}}
لا تمثل بناءً خاصا، بل هو كائن JavaScript المعروف {}
والمعرف بداخل الأقواس المعقوفة الخاصة بال JSX بداخل style={ }
. يمكنك استخدام خاصية style
عندما يكون التصميم لديك معتمدا على متغير JavaScript.
التصيير الشرطي
في React، لا يوجد طريقة خاصة لكتابة العبارات الشرطية، وإنما يتم استخدام نفس الطرق المستخدمة في كتابة أكواد JavaScript الاعتيادية، فعلى سبيل المثال يمكنك استخدام عبارة if
لإظهار الـ JSX بشكل شرطي:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
و إذا كنت تفضل استخدام كود أكثر اختصارا فيمكنك استخدام معامل ?
الشرطي وتتميز بإمكانية استخدامها في داخل ال JSX على النقيض من if
العادية.
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
و في حالة عدم احتياجك لجزئية else
فيمكنك استخدام عبارة &&
المنطقية:
<div>
{isLoggedIn && <AdminPanel />}
</div>
كل الطرق المذكورة في الأعلى يمكن كذلك استخدامها لتحديد قيم الخواص بشكل شرطي. إذا كان هذا النوع من جمل JavaScript غير مألوفا لديك فيمكنك دائما استخدام عبارة if...else
الاعتيادية.
تصيير القوائم
ستحتاج إلى الاعتماد على ميزات Javascript مثل for
loop وكذلك دالة map()
الخاصة بالمصفوفات لإظهار القوائم على المكوّنات.
على سبيل المثال، لنفترض أن لديك مصفوفة لمجموعة من المنتجات كالتالي:
const products = [
{ title: 'ملفوف', id: 1 },
{ title: 'خضروات', id: 2 },
{ title: 'تفاح', id: 3 },
];
قم باستخدام دالة map()
بداخل المكوّن الخاص بك لتحويل مصفوفة المنتجات إلى مصفوفة من عناصر الـ <li>
:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
لاحظ أن كل <li>
لديه خاصية باسم key
. كل عنصر في أي قائمة يجب أن يتم تمرير رقم أو سلسلة نصية إليه لتميّزه عن كل العناصر الأخرى الموجودة في نفس القائمة. هذه الخاصية عادة ما يتم تعبئتها من صلب البيانات الخاصة بمشروعك مثل الـ ID الخاص بقاعدة البيانات. هذا المفتاح (key) يتم استخدامه من React ولمعرفة ما الذي حدث تحديدا في حال قمت لاحقا بإضافة، حذف أو إعادة ترتيب لعناصر القائمة.
const products = [ { title: 'ملفوف', isFruit: false, id: 1 }, { title: 'خضروات', isFruit: false, id: 2 }, { title: 'تفاح', isFruit: true, id: 3 }, ]; export default function ShoppingList() { const listItems = products.map(product => <li key={product.id} style={{ color: product.isFruit ? 'magenta' : 'darkgreen' }} > {product.title} </li> ); return ( <ul>{listItems}</ul> ); }
الاستجابة للأحداث
يمكنك الاستجابة للأحداث عن طريق تعريف (معالج الحدث) أو الـ event handler بداخل المكوّن الخاص بك:
function MyButton() {
function handleClick() {
alert('لقد ضغطت هنا!');
}
return (
<button onClick={handleClick}>
اضغط هنا
</button>
);
}
لاحظ أن onClick={handleClick}
لا تحتوي على أقواس الاستدعاء في النهاية! لا تقم باستدعاء معالج الحدث، يكفيك أن تقوم بتمرير اسمها فقط. حيث أن React ستقوم باستدعاء دالة معالجة الحدث عندما يقوم المستخدم بالضغط على الزر.
تحديث الشاشة
غالبا ستحتاج أن “يتذكر” المكوّن المعلومات ويعرضها على الشاشة. فمثلا، قد تحتاج إلى عرض عدد المرات التي تم فيها الضغط على زر ما. لتنفيذ ذلك قم بإضافة ما يعرف ب حالة أو الـ state الخاصة بالمكون:
في البداية، قم باستيراد useState
من React:
import { useState } from 'react';
والآن يمكنك تعريف متغير الحالة أو الـ state variable بداخل المكوّن:
function MyButton() {
const [count, setCount] = useState(0);
// ...
ستحصل على شيئين من دالة useState
: الحالة الحالية (count
)، وكذلك الدالة التي تمكنك من تحديث القيمة (setCount
). يمكنك تسميتهما ما تشاء، ولكن المتعارف عليه أن يتم تسميتها بالشكل التالي: [something, setSomething]
.
في المرة الأولى التي يظهر فيها الزر ستكون قيمة coount
تساوي 0
وذلك لأنك قمت بتمرير 0
كبارامتر لدالة useState()
. عندما تريد تغيير الحالة، قم باستدعاء setCount()
وتمرير القيمة الجديدة لها. وبالتالي فإن الضغط على هذا الزر سيزيد العداد count
.
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
الآن ستقوم React باستدعاء المكوّن الخاص بك مجددا. في هذه المرة قيمة count
ستكون 1
، ومن ثم ستكون 2
، وهكذا.
إذا قمت تصيير المكوّن عدة مرات فإن كل مرة ستكون لها الحالة المستقلة الخاصة بها. قم بتجربة الضغط على كل زر على حدة:
import { useState } from 'react'; export default function MyApp() { return ( <div> <h1>العدادات التي تتغير مستقلة</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Clicked {count} times </button> ); }
لاحظ كيف أن كل زر قادر على “تذكر” حالة الـ count
الخاصة به دون أي تعارض مع حالة الزر الآخر.
استخدام الخطافات
الدوال التي تبدأ بـ use
تسمى الخطافات أو Hooks. تعتبر useState
أحد الخطافات المجهّزة والتي توفرها React. وبإمكانك العثور على قائمة الخطافات المختلفة التي توفرها React في API مرجع. ، يمكنك كذلك كتابة الخطافات الخاصة بك عن طريق الجمع بين الخطافات الجاهزة والموفّرة من React.
الخطافات أكثر صرامة من الدوال الأخرى. يمكنك استدعاء الخطاف في مقدمة المكوّن (أو في مقدمة أي خطاف آخر). إذا أردت استخدام useState
في عبارة شرطية أو في حملة تكرار فقم ببناء مكوّن مستقل ومن ثم استخدامها هناك.
مشاركة البيانات بين المكوّنات
في المثال السابق، كل MyButton
كان لديه حالة الـ count
المستقلة الخاصة به، وعندما يتم الضغط على أي منهما حينها يتم تعديل الـ count
الخاصة بذلك الزر فقط:
و بالرغم من ذلك، فإنك غالبا ستحتاج أن تشارك المكوّنات البيانات وأن يتم تحديثها معا
و لجعل كلا المكونين MyButton
يقومان بعرض نفس الـ count
ويتم تحديثهما معا فسنحتاج إلى نقل الحالة من كل زر بشكل مستقل “إلى الأعلى” لأقرب مكوّن يحوي كلا المكوّنين.
في هذا المثال MyApp
يمثل هذا هذا المكون الأب الذي يحوي كل المكونين:
و الآن عند الضغط على أي من الزرين، فإن الـ count
في MyApp
ستتغير، وبالتالي سيغير ذلك بدوره كلا العدادين المتواجدين في MyButton
. يمكنك تمثيل ذلك بالكود كالتالي:
في البداية قم بنقل الحالة للأعلى من MyButton
إلى MyApp
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>العدادات التي تتغير مستقلة</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... نقلت كودا من هنا ...
}
و من ثم قم بتمرير الحالة للأسفل من MyApp
لكلا مكوّني الـ MyButton
بالإضافة إلى دالة معالجة الضغط على الزر (click handler). بإمكانك إرسال معلومات إلى MyButton
باستخدام أقواس الـ JSX المعقوفة، تماما كما فعلت سابقا في الأوسمة الجاهزة مثل وسم <img>
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>العدادات التي تتغير معا</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
هذه المعلومات التي تقوم بتمريرها للأسفل تسمى props أو خواص المكوّن. والآن مكون MyApp
يحتوي على حالة الـ count
بالإضافة لمعالج الحدث باسم handleClick
، ويقوم بإرسالهما للأسفل لكلا الزرين.
أخيرا غيًر كود MyButton
ليقرأ خواص المكوّن التي قمت بتمريرها إليه من مكوّن الأب:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
ضغطت {count} مرات
</button>
);
}
عندما تقوم بالضغط على الزر سيتم تشغيل معالج الحدث الذي يحمل اسم onClick
. خاصية معالجة الحدث المرسلة لكلا الزرين والتي تحمل اسم onClick
في كليهما هي في حقيقة الأمر تمثل دالة الـ handleClick
المعرّفة بداخل الـ MyApp
، وبالتالي سيتم تنفيذ الكود المعرّف بداخلها. ذلك الكود سيقوم باستدعاء setCount(count + 1)
، والذي بدوره سيزيد حالة الـ count
. ومن ثم فإن القيمة الجديدة للـ count
سيتم تمريرها لكلي الزرين وبالتالي فإن كليهما سيُظهران نفس القيمة. هذا ما يعرف بـ “نقل الحالة للأعلى”. بنقلك للحالة للأعلى تكون قد جعلت الحالة مشتركة بين المكوّنات.
import { useState } from 'react'; export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>العدادات التي تتغير معًا</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); } function MyButton({ count, onClick }) { return ( <button onClick={onClick}> ضغطت {count} مرات </button> ); }
الخطوات القادمة
والآن أنت تعرف أساسيات بناء كود React! اطّلع على هذا الدرس التطبيقي لتفعيل هذه الأساسيات بشكل عملي وبناء مشروعك المصغّر الأوّل باستخدام React.