EduFlow
أساسيات React
⁦0%⁩

الوحدة 2 · الـ Components والـ Props

التفكير بالـ components

16 دقراءة 3 داختر بحكمة

الدرس في لمحة

حوّل تصميم الشاشة إلى شجرة components، وابنِ نسخة ثابتة أولًا، وحدّد أقل قدر من الـ state يحتاجه Watchlist قبل كتابة أي كود تفاعلي.

  1. 1ارسم صناديق وسمِّها
  2. 2متى تقسّم، ومتى لا تفعل
  3. 3ابنِ النسخة الثابتة أولًا
  4. 4اعثر على أقل قدر من الـ state
  5. 5أين تعيش البيانات

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

هذا هو Watchlist الذي تبنيه، موصوفًا كما يسلّمه المصمّم: ترويسة فيها العنوان وعبارة «3 to watch»؛ ونموذج فيه حقل لعنوان الفيلم وزر Add؛ وصف من أزرار الفلترة (All وTo watch وWatched)؛ وقائمة أفلام، لكل فيلم عنوانه وسنته ومربّع اختيار لتعليمه كمُشاهَد. وحين تكون القائمة فارغة، تحلّ محلّها رسالة ودودة.

قبل أن تكتب سطرًا واحدًا من الكود، قرّر ما هي الـ components. هذه أهم خطوة تصميمية في تطبيق React، وتُنجَز بالقلم.

ارسم صناديق وسمِّها

خذ التصميم وارسم صندوقًا حول كل قطعة تؤدّي عملًا واحدًا. ثم سمِّ كل صندوق باسم، كما تسمّي دالة.

App هو الجذر، وأبناؤه Header وAddMovieForm وFilterBar وMovieList. يحتوي Header على WatchCount. ويحتوي MovieList على عدّة components من نوع MovieItem، أو على EmptyState حين لا توجد أفلام. App Header AddMovieForm FilterBar MovieList WatchCount MovieItem ×n EmptyState
تطبيق Watchlist على شكل شجرة components

الصناديق المتداخلة تصبح شجرة. يملك App الشاشة كلها. ويرسم MovieList إمّا عدّة MovieItem وإمّا EmptyState واحدًا. هذه الشجرة هي خطة بقية الدورة؛ ستبني كل صندوق فيها كـ component.

متى تقسّم، ومتى لا تفعل

اجعل القطعة component مستقلًا إذا تحقّق واحد على الأقل مما يلي:

  • تتكرّر. يظهر MovieItem مرة لكل فيلم، والغاية أن تكتبه مرة واحدة.
  • لها عمل خاص بها. يتولّى AddMovieForm الكتابة والإرسال، ولا يحتاج أي جزء آخر إلى معرفة كيف يفعل ذلك.
  • الأب صار صعب القراءة. إن كنت تحتاج إلى التمرير لتفهم component، فاستخرج منه قطعة لها اسم.

لا تقسّم لمجرد أنك تستطيع. الـ component الذي لا يفعل سوى تغليف <span> واحد يضيف ملفًا وسطر import واسمًا عليك تذكّره، ولا يعطيك شيئًا في المقابل. الفرق المتمرّسة كثيرًا ما تُبقي component من 100 سطر بدل أن تقسّمه إلى خمسة من 20 سطرًا لا تُستخدم إلا معًا. ابدأ بحجم أكبر قليلًا، واستخرج القطع حين يظهر أحد الأسباب الثلاثة.

ابنِ النسخة الثابتة أولًا

بعد رسم الشجرة، ابنِها ببيانات مكتوبة يدويًا ومن دون أي تفاعل. مرّر البيانات من الأعلى إلى الأسفل حتى يكون الشكل صحيحًا من البداية:

src/App.jsx
const MOVIES = [
  { id: 1, title: 'Arrival', year: 2016, watched: true },
  { id: 2, title: 'Past Lives', year: 2023, watched: false },
  { id: 3, title: 'Paddington 2', year: 2017, watched: false },
];

export default function App() {
  return (
    <main>
      <Header movies={MOVIES} />
      <AddMovieForm />
      <FilterBar />
      <MovieList movies={MOVIES} />
    </main>
  );
}
// …Header, AddMovieForm, FilterBar and MovieList defined below

بناء النسخة الثابتة كتابة في معظمه، وهو يضبط البنية والـ markup بينما لا شيء يتحرّك. أمّا إضافة التفاعل فتفكير في معظمها. والقيام بالأمرين معًا هو الطريق الذي تنتهي به الـ components متشابكة.

اعثر على أقل قدر من الـ state

بعد ذلك، اكتب قائمة بكل قطعة بيانات في التطبيق، واطرح على كل واحدة ثلاثة أسئلة: هل تبقى ثابتة مع الوقت؟ هل تأتي من الأب؟ هل يمكنك حسابها من بيانات أخرى؟ إذا كان الجواب نعم على أيٍّ منها، فهي ليست state.

بالنسبة إلى Watchlist:

البيانات state؟ السبب
قائمة الأفلام نعم تتغيّر حين تضيف فيلمًا أو تحذفه أو تعلّمه
الفلتر الحالي نعم يتغيّر حين تنقر زر فلترة
النص المكتوب في النموذج نعم يتغيّر أثناء الكتابة
عدد الأفلام المتبقية لا يُحسب من الأفلام
الأفلام الظاهرة حاليًا لا تُحسب من الأفلام + الفلتر

ثلاث قطع من الـ state، وقيمتان مشتقّتان. إبقاء الـ state في حدّه الأدنى هو العادة الوحيدة التي تمنع أكبر عدد من الأخطاء في تطبيقات React. فكل قطعة state إضافية نسخة ثانية من الحقيقة قد تختلف عن الأولى.

أين تعيش البيانات

يحتاج Header إلى الأفلام (من أجل العدد)، ويحتاجها MovieList (لعرضها). والقاعدة: تعيش البيانات في أقرب أب مشترك لكل الـ components التي تحتاجها، وهو هنا App. وتنزل منه كـ props. وحين يحتاج ابنٌ إلى تغييرها، يمرّر له الأب دالة يستدعيها. ستفعل هذا تحديدًا في القسم 3.

في الدرس التالي تتعلّم الـ props كما يجب: كيف تمرّر البيانات إلى الـ components، وتضبط القيم الافتراضية، وتُبقي الـ components قابلة لإعادة الاستخدام.

أهم النقاط

  • ارسم صناديق حول التصميم وسمِّ كل صندوق؛ الصناديق المتداخلة تصبح شجرة components.
  • قسّم الـ component حين تتكرّر قطعة منه، أو يكون لها عمل مستقل، أو حين يصعب قراءة الأب، لا لمجرد العادة.
  • ابنِ نسخة ثابتة من بيانات مكتوبة يدويًا أولًا، ثم أضف التفاعل.
  • احتفظ بأقل قدر من الـ state؛ فكل ما يمكن حسابه من بيانات أخرى، كالعدد أو القائمة المصفّاة، قيمة مشتقّة وليس state.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

يحتاج Watchlist إلى عرض عدد الأفلام غير المُشاهَدة. من أين يجب أن يأتي هذا الرقم؟

السؤال 2 من 4

قسّم زميلك بطاقة الفيلم إلى MovieTitle وMovieYear وMovieTitleWrapper وMovieYearText، وكلٌّ منها يغلّف وسمًا واحدًا. ما أفضل تعليق في مراجعة الكود؟

السؤال 3 من 4

في شجرة Watchlist، يحتوي App على Header وAddMovieForm وFilterBar وMovieList، ويحتوي MovieList على كثير من MovieItem. أيّ الـ components تحتاج إلى مصفوفة الأفلام؟

السؤال 4 من 4

لماذا تبني نسخة ثابتة من Watchlist ببيانات مكتوبة يدويًا قبل إضافة الـ state؟

تدريب

اختر بحكمة

اعثر على أقل قدر من الـ state

يحصل Watchlist على ميزتين جديدتين. صار بإمكان كل فيلم أن يحمل تقييمًا من 1 إلى 5 نجوم تضبطه بالنقر على النجوم، وصارت هناك قائمة منسدلة تتيح ترتيب القائمة حسب العنوان أو حسب السنة. وتعرض الترويسة أيضًا متوسّط تقييم الأفلام التي شاهدتها.

أيٌّ من هذه يجب تخزينه في الـ state؟ اختر كل ما هو state فعلًا، واترك كل ما هو مشتقّ.

اعثر على أقل قدر من الـ state