logo by @sawaratsuki1004
React
v19.2
Learn
Reference
Community
Blog

Is this page useful?

في هذه الصفحة

  • Overview
  • رفع الحالة لأعلى بالمثال
  • الخطوة 1: إزالة الحالة من المكونات الفرعية
  • الخطوة 2: تمرير بيانات مكتوبة بشكل ثابت من الأب المشترك
  • الخطوة 3: إضافة حالة إلى الأب المشترك
  • مصدر حقيقة واحد لكل حالة
  • Recap
  • Challenges

    البدأ

  • بداية سريعة
    • شرح تطبيقي: لعبة تيك تاك تو
    • التفكير على طريقة React
  • التثبيت
    • إنشاء تطبيق React
    • بناء تطبيق React من الصفر
    • إضافة React إلى مشروع موجود بالفعل
  • الإعداد
    • تجهيز المحرر
    • استخدام TypeScript
    • أدوات مطوري React
  • React Compiler
    • مقدمة
    • التثبيت
    • التبني التدريجي
    • تصحيح الأخطاء واستكشاف المشاكل
  • تعلم React

  • وصف واجهة المستخدم (UI)
    • مكونك الأول (Component)
    • استيراد وتصدير المكونات (Components)
    • كتابة ترميز البناء بـ JSX
    • JavaScript في JSX باستخدام الأقواس المنحنية
    • تمرير الخصائص (Props) إلى مكون
    • التصيير الشرطي (Conditional Rendering)
    • تصيير القوائم (Rendering Lists)
    • الحفاظ على نقاء المكونات (Pure Components)
    • واجهتك المستخدم كشجرة (UI Tree)
  • إضافة التفاعلية (Interactivity)
    • الاستجابة للأحداث (Events)
    • الحالة (State): ذاكرة المُكَوِّن
    • التصيير والالتزام (Render and Commit)
    • الحالة (State) كلقطة
    • إضافة سلسلة من تحديثات الحالة (State) إلى قائمة انتظار
    • تحديث الكائنات (Objects) في الحالة
    • تحديث المصفوفات (Arrays) في الحالة
  • إدارة State
    • التفاعل مع Input باستخدام State
    • اختيار بنية State
    • مشاركة State بين Components
    • الحفاظ على State وإعادة ضبطها
    • استخراج منطق State إلى Reducer
    • تمرير البيانات بشكل عميق باستخدام Context
    • التوسع باستخدام Reducer و Context
  • مخارج الطوارئ (Escape Hatches)
    • الإشارة إلى القيم باستخدام Refs
    • التلاعب بـ DOM باستخدام Refs
    • التزامن مع Effects
    • قد لا تحتاج إلى Effect
    • دورة حياة Reactive Effects
    • فصل Events عن Effects
    • إزالة اعتماديات Effect
    • إعادة استخدام المنطق باستخدام Custom Hooks
تعلم React
إدارة State

مشاركة الحالة بين المكونات

أحيانًا، تريد أن تتغير حالة مكونين معًا دائمًا. للقيام بذلك، أزل الحالة من كليهما، وانقلها إلى أقرب مكون أب مشترك، ثم مررها إليهما عبر props. يُعرف هذا باسم رفع الحالة لأعلى، وهو أحد أكثر الأشياء شيوعًا التي ستفعلها عند كتابة كود React.

You will learn

  • كيفية مشاركة الحالة بين المكونات من خلال رفعها لأعلى
  • ما هي المكونات المتحكم فيها وغير المتحكم فيها

رفع الحالة لأعلى بالمثال

في هذا المثال، يصيّر مكون Accordion الأب مكونين منفصلين من Panel:

  • Accordion
    • Panel
    • Panel

كل مكون Panel لديه حالة isActive من نوع boolean تحدد ما إذا كان محتواه مرئيًا.

اضغط على زر Show لكلا اللوحتين:

import { useState } from 'react'; function Panel({ title, children }) { const [isActive, setIsActive] = useState(false); return ( <section className="panel"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={() => setIsActive(true)}> Show </button> )} </section> ); } export default function Accordion() { return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title="About"> With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title="Etymology"> The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); }

لاحظ أن الضغط على زر لوحة واحدة لا يؤثر على اللوحة الأخرى — فهما مستقلتان.

رسم تخطيطي يوضح شجرة من ثلاثة مكونات، أب واحد باسم Accordion واثنان من الأبناء باسم Panel. كلا مكوني Panel يحتويان على isActive بقيمة false.
رسم تخطيطي يوضح شجرة من ثلاثة مكونات، أب واحد باسم Accordion واثنان من الأبناء باسم Panel. كلا مكوني Panel يحتويان على isActive بقيمة false.

في البداية، حالة isActive لكل Panel هي false، لذا يظهران منطويين

نفس الرسم التخطيطي السابق، مع تمييز isActive لمكون Panel الأول الطفل مع الإشارة إلى نقرة مع تعيين قيمة isActive إلى true. مكون Panel الثاني لا يزال يحتوي على القيمة false.
نفس الرسم التخطيطي السابق، مع تمييز isActive لمكون Panel الأول الطفل مع الإشارة إلى نقرة مع تعيين قيمة isActive إلى true. مكون Panel الثاني لا يزال يحتوي على القيمة false.

النقر على زر أي Panel سيحدّث حالة isActive لذلك Panel فقط

لكن الآن دعنا نقول أنك تريد تغييره بحيث يتم توسيع لوحة واحدة فقط في أي وقت. مع هذا التصميم، يجب أن يؤدي توسيع اللوحة الثانية إلى طي اللوحة الأولى. كيف ستفعل ذلك؟

لتنسيق هاتين اللوحتين، تحتاج إلى “رفع حالتهما لأعلى” إلى مكون أب في ثلاث خطوات:

  1. أزل الحالة من المكونات الفرعية.
  2. مرر بيانات مكتوبة بشكل ثابت من الأب المشترك.
  3. أضف حالة إلى الأب المشترك ومررها مع معالجات الأحداث.

سيسمح هذا لمكون Accordion بتنسيق كلا Panel وتوسيع واحد فقط في كل مرة.

الخطوة 1: إزالة الحالة من المكونات الفرعية

ستمنح التحكم في isActive لـ Panel إلى مكونه الأب. هذا يعني أن مكون الأب سيمرر isActive إلى Panel كـ prop بدلاً من ذلك. ابدأ بـ إزالة هذا السطر من مكون Panel:

const [isActive, setIsActive] = useState(false);

وبدلاً من ذلك، أضف isActive إلى قائمة props لـ Panel:

function Panel({ title, children, isActive }) {

الآن يمكن لمكون أب Panel التحكم في isActive من خلال تمريرها كـ prop. على العكس، مكون Panel الآن ليس لديه سيطرة على قيمة isActive — الأمر الآن متروك لمكون الأب!

الخطوة 2: تمرير بيانات مكتوبة بشكل ثابت من الأب المشترك

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

  • Accordion (أقرب أب مشترك)
    • Panel
    • Panel

في هذا المثال، إنه مكون Accordion. نظرًا لأنه فوق كلا اللوحتين ويمكنه التحكم في props الخاصة بهما، فسيصبح “مصدر الحقيقة” للوحة النشطة حاليًا. اجعل مكون Accordion يمرر قيمة مكتوبة بشكل ثابت من isActive (على سبيل المثال، true) إلى كلا اللوحتين:

import { useState } from 'react'; export default function Accordion() { return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title="About" isActive={true}> With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title="Etymology" isActive={true}> The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); } function Panel({ title, children, isActive }) { return ( <section className="panel"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={() => setIsActive(true)}> Show </button> )} </section> ); }

حاول تحرير قيم isActive المكتوبة بشكل ثابت في مكون Accordion وشاهد النتيجة على الشاشة.

الخطوة 3: إضافة حالة إلى الأب المشترك

رفع الحالة لأعلى غالبًا ما يغير طبيعة ما تخزنه كحالة.

في هذه الحالة، يجب أن تكون لوحة واحدة فقط نشطة في كل مرة. هذا يعني أن مكون الأب المشترك Accordion يحتاج إلى تتبع أي لوحة هي النشطة. بدلاً من قيمة boolean، يمكن أن يستخدم رقمًا كمؤشر للـ Panel النشطة لمتغير الحالة:

const [activeIndex, setActiveIndex] = useState(0);

عندما يكون activeIndex هو 0، تكون اللوحة الأولى نشطة، وعندما يكون 1، تكون الثانية.

النقر على زر “Show” في أي Panel يحتاج إلى تغيير المؤشر النشط في Accordion. لا يمكن لـ Panel تعيين حالة activeIndex مباشرة لأنها معرّفة داخل Accordion. يحتاج مكون Accordion إلى السماح بشكل صريح لمكون Panel بتغيير حالته من خلال تمرير معالج حدث كـ prop:

<> <Panel isActive={activeIndex === 0} onShow={() => setActiveIndex(0)} > ... </Panel> <Panel isActive={activeIndex === 1} onShow={() => setActiveIndex(1)} > ... </Panel> </>

الآن سيستخدم <button> داخل Panel خاصية onShow كمعالج حدث النقر الخاص به:

import { useState } from 'react'; export default function Accordion() { const [activeIndex, setActiveIndex] = useState(0); return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title="About" isActive={activeIndex === 0} onShow={() => setActiveIndex(0)} > With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title="Etymology" isActive={activeIndex === 1} onShow={() => setActiveIndex(1)} > The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); } function Panel({ title, children, isActive, onShow }) { return ( <section className="panel"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={onShow}> Show </button> )} </section> ); }

هذا يكمل رفع الحالة لأعلى! نقل الحالة إلى مكون الأب المشترك سمح لك بتنسيق اللوحتين. استخدام المؤشر النشط بدلاً من علامتين “is shown” ضمن أن لوحة واحدة فقط نشطة في أي وقت معين. وتمرير معالج الحدث إلى الطفل سمح للطفل بتغيير حالة الأب.

رسم تخطيطي يوضح شجرة من ثلاثة مكونات، أب واحد باسم Accordion واثنان من الأبناء باسم Panel. يحتوي Accordion على قيمة activeIndex صفر والتي تتحول إلى قيمة isActive صحيحة ممررة إلى Panel الأول، وقيمة isActive خاطئة ممررة إلى Panel الثاني.
رسم تخطيطي يوضح شجرة من ثلاثة مكونات، أب واحد باسم Accordion واثنان من الأبناء باسم Panel. يحتوي Accordion على قيمة activeIndex صفر والتي تتحول إلى قيمة isActive صحيحة ممررة إلى Panel الأول، وقيمة isActive خاطئة ممررة إلى Panel الثاني.

في البداية، activeIndex لـ Accordion هو 0، لذا يتلقى Panel الأول isActive = true

نفس الرسم التخطيطي السابق، مع تمييز قيمة activeIndex لمكون Accordion الأب مع الإشارة إلى نقرة مع تغيير القيمة إلى واحد. التدفق إلى كلا مكوني Panel الطفلين مميز أيضًا، وقيمة isActive الممررة لكل طفل معينة على العكس: false للـ Panel الأول و true للثاني.
نفس الرسم التخطيطي السابق، مع تمييز قيمة activeIndex لمكون Accordion الأب مع الإشارة إلى نقرة مع تغيير القيمة إلى واحد. التدفق إلى كلا مكوني Panel الطفلين مميز أيضًا، وقيمة isActive الممررة لكل طفل معينة على العكس: false للـ Panel الأول و true للثاني.

عندما تتغير حالة activeIndex لـ Accordion إلى 1، يتلقى Panel الثاني isActive = true بدلاً من ذلك

غوص عميق

المكونات المتحكم فيها وغير المتحكم فيها

من الشائع تسمية مكون بحالة محلية “غير متحكم فيه”. على سبيل المثال، مكون Panel الأصلي مع متغير حالة isActive غير متحكم فيه لأن أبوه لا يمكنه التأثير على ما إذا كانت اللوحة نشطة أم لا.

في المقابل، قد تقول أن مكونًا “متحكم فيه” عندما تكون المعلومات المهمة فيه مدفوعة بـ props بدلاً من حالته المحلية الخاصة. هذا يتيح لمكون الأب تحديد سلوكه بالكامل. مكون Panel النهائي مع خاصية isActive متحكم فيه بواسطة مكون Accordion.

المكونات غير المتحكم فيها أسهل في الاستخدام داخل آبائها لأنها تتطلب تكوينًا أقل. لكنها أقل مرونة عندما تريد تنسيقها معًا. المكونات المتحكم فيها مرنة إلى أقصى حد، لكنها تتطلب من مكونات الأب تكوينها بالكامل بـ props.

في الممارسة العملية، “متحكم فيه” و “غير متحكم فيه” ليست مصطلحات تقنية صارمة — كل مكون عادة ما يكون لديه مزيج من كل من الحالة المحلية و props. ومع ذلك، هذه طريقة مفيدة للحديث عن كيفية تصميم المكونات والقدرات التي تقدمها.

عند كتابة مكون، ضع في اعتبارك أي معلومات فيه يجب أن تكون متحكم فيها (عبر props)، وأي معلومات يجب أن تكون غير متحكم فيها (عبر state). ولكن يمكنك دائمًا تغيير رأيك وإعادة الهيكلة لاحقًا.

مصدر حقيقة واحد لكل حالة

في تطبيق React، سيكون للعديد من المكونات حالتها الخاصة. قد “تعيش” بعض الحالات بالقرب من المكونات الورقية (المكونات في أسفل الشجرة) مثل المدخلات. قد “تعيش” حالات أخرى بالقرب من أعلى التطبيق. على سبيل المثال، حتى مكتبات routing من جانب client عادة ما يتم تنفيذها من خلال تخزين المسار الحالي في حالة React، وتمريره بـ props!

لكل جزء فريد من الحالة، ستختار المكون الذي “يمتلكه”. هذا المبدأ معروف أيضًا باسم وجود “مصدر حقيقة واحد”. لا يعني ذلك أن كل الحالات تعيش في مكان واحد — ولكن لـ كل جزء من الحالة، هناك مكون محدد يحتوي على تلك القطعة من المعلومات. بدلاً من تكرار الحالة المشتركة بين المكونات، ارفعها لأعلى إلى الأب المشترك الخاص بها، و مررها لأسفل إلى الأطفال الذين يحتاجون إليها.

سيتغير تطبيقك أثناء عملك عليه. من الشائع أن تنقل الحالة لأسفل أو للخلف بينما لا تزال تكتشف أين “تعيش” كل قطعة من الحالة. هذا كله جزء من العملية!

لمعرفة ما يبدو عليه هذا في الممارسة مع المزيد من المكونات، اقرأ التفكير على طريقة React.

خلاصة

  • عندما تريد تنسيق مكونين، انقل حالتهما إلى أبيهما المشترك.
  • ثم مرر المعلومات عبر props من أبيهما المشترك.
  • أخيرًا، مرر معالجات الأحداث بحيث يمكن للأطفال تغيير حالة الأب.
  • من المفيد اعتبار المكونات “متحكم فيها” (مدفوعة بـ props) أو “غير متحكم فيها” (مدفوعة بـ state).

جرّب بعض التحديات

تحدي 1 من 2:
مدخلات متزامنة

هذان المدخلان مستقلان. اجعلهما متزامنين: تحرير مدخل واحد يجب أن يحدّث المدخل الآخر بنفس النص، والعكس صحيح.

import { useState } from 'react'; export default function SyncedInputs() { return ( <> <Input label="First input" /> <Input label="Second input" /> </> ); } function Input({ label }) { const [text, setText] = useState(''); function handleChange(e) { setText(e.target.value); } return ( <label> {label} {' '} <input value={text} onChange={handleChange} /> </label> ); }
السابقاختيار بنية State
التاليالحفاظ على State وإعادة ضبطها

Copyright © Meta Platforms, Inc
no uwu plz
uwu?
Logo by@sawaratsuki1004
تعلم React
بداية سريعة
التثبيت
وصف واجهة المستخدم (UI)
إضافة التفاعلية
إدارة State
مخارج الطوارئ
مرجع API
React APIs
React DOM APIs
المجتمع
ميثاق السلوك
تعرف على الفريق
المساهمون في التوثيق
شكر وتقدير
المزيد
المدونة
React Native
الخصوصية
الشروط
Fork
import { useState } from 'react';

function Panel({ title, children }) {
  const [isActive, setIsActive] = useState(false);
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={() => setIsActive(true)}>
          Show
        </button>
      )}
    </section>
  );
}

export default function Accordion() {
  return (
    <>
      <h2>Almaty, Kazakhstan</h2>
      <Panel title="About">
        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
      </Panel>
      <Panel title="Etymology">
        The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
      </Panel>
    </>
  );
}

const [isActive, setIsActive] = useState(false);
function Panel({ title, children, isActive }) {
Fork
import { useState } from 'react';

export default function Accordion() {
  return (
    <>
      <h2>Almaty, Kazakhstan</h2>
      <Panel title="About" isActive={true}>
        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
      </Panel>
      <Panel title="Etymology" isActive={true}>
        The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
      </Panel>
    </>
  );
}

function Panel({ title, children, isActive }) {
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={() => setIsActive(true)}>
          Show
        </button>
      )}
    </section>
  );
}

const [activeIndex, setActiveIndex] = useState(0);
<>
<Panel
isActive={activeIndex === 0}
onShow={() => setActiveIndex(0)}
>
...
</Panel>
<Panel
isActive={activeIndex === 1}
onShow={() => setActiveIndex(1)}
>
...
</Panel>
</>
Fork
import { useState } from 'react';

export default function Accordion() {
  const [activeIndex, setActiveIndex] = useState(0);
  return (
    <>
      <h2>Almaty, Kazakhstan</h2>
      <Panel
        title="About"
        isActive={activeIndex === 0}
        onShow={() => setActiveIndex(0)}
      >
        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
      </Panel>
      <Panel
        title="Etymology"
        isActive={activeIndex === 1}
        onShow={() => setActiveIndex(1)}
      >
        The name comes from <span lang="kk-KZ">алма</span>, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang="la">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.
      </Panel>
    </>
  );
}

function Panel({
  title,
  children,
  isActive,
  onShow
}) {
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={onShow}>
          Show
        </button>
      )}
    </section>
  );
}

Fork
import { useState } from 'react';

export default function SyncedInputs() {
  return (
    <>
      <Input label="First input" />
      <Input label="Second input" />
    </>
  );
}

function Input({ label }) {
  const [text, setText] = useState('');

  function handleChange(e) {
    setText(e.target.value);
  }

  return (
    <label>
      {label}
      {' '}
      <input
        value={text}
        onChange={handleChange}
      />
    </label>
  );
}