الفرق بين المراجعتين ل"React/conditional rendering"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(تحديث)
 
(7 مراجعات متوسطة بواسطة 3 مستخدمين غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:التصيير الشرطي (Conditional Rendering)‎}}</noinclude>
+
<noinclude>{{DISPLAYTITLE:التصيير الشرطي في React‎}}</noinclude>
 +
بإمكانك في React إنشاء مُكوِّنات مميّزة تُغلِّف السلوك الذي تريده، ثم بعد ذلك تُصيِّر فقط أجزاء منها اعتمادًا على حالة تطبيقك.
 +
 
 +
يعمل التصيير الشرطي (Conditional rendering) في React بنفس الطريقة التي تعمل فيها التعابير الشرطيّة في [[JavaScript]]، حيث تستطيع استخدام مُعامِلات [[JavaScript]] مثل [[JavaScript/if...else|if]] أو [[JavaScript/Conditional Operator|المُعامِل الشرطي]] لإنشاء عناصر تُمثِّل الحالة الحاليّة، ثمّ تدع React تُحدِّث واجهة المستخدم لمُطابقتها.
 +
 
 +
فلننظر إلى هذين المُكوِّنين:<syntaxhighlight lang="javascript">
 +
function UserGreeting(props) {
 +
  return <h1>أهلًا بعودتك!</h1>;
 +
}
 +
 
 +
function GuestGreeting(props) {
 +
  return <h1>يرجى التسجيل في الموقع</h1>;
 +
}
 +
 
 +
</syntaxhighlight>سنُنشِئ مُكوِّن الترحيب <code>Greeting</code> الذي يعرض واحدًا من هذين المُكوِّنين بحسب حالة المستخدم إن كان قيد تسجيل الدخول أم لا:<syntaxhighlight lang="javascript">
 +
function Greeting(props) {
 +
  const isLoggedIn = props.isLoggedIn;
 +
  if (isLoggedIn) {
 +
    return <UserGreeting />;
 +
  }
 +
  return <GuestGreeting />;
 +
}
 +
 
 +
ReactDOM.render(
 +
  // جرب التغيير إلى isLoggedIn={true}
 +
  <Greeting isLoggedIn={false} />,
 +
  document.getElementById('root')
 +
);
 +
 
 +
</syntaxhighlight>[https://codepen.io/gaearon/pen/ZpVxNq?editors=0011 جرِّب المثال على موقع CodePen].
 +
 
 +
يعرض هذا المثال ترحيبًا مختلفًا اعتمادًا على قيمة الخاصيّة <code>isLoggedIn</code>.
 +
 
 +
== متغيرات العناصر ==
 +
بإمكانك استخدام المتغيّرات لتخزين العناصر، يُساعد هذا على تصيير جزء من المُكوِّن بشكل شرطي بحيث لا تتغير بقية ناتجه.
 +
 
 +
فلنأخذ هذين المُكوِّنين الجديدين اللذين يُمثِّلان أزرار تسجيل الخروج (Logout) وتسجيل الدخول (Login):<syntaxhighlight lang="javascript">
 +
function LoginButton(props) {
 +
  return (
 +
    <button onClick={props.onClick}>
 +
      تسجيل الدخول
 +
    </button>
 +
  );
 +
}
 +
 
 +
function LogoutButton(props) {
 +
  return (
 +
    <button onClick={props.onClick}>
 +
      تسجيل الخروج
 +
    </button>
 +
  );
 +
}
 +
 
 +
</syntaxhighlight>في المثال السّابق سنُنشِئ مُكوِّن له حالة وسنُسمّيه <code>LoginControl</code>.
 +
 
 +
سيُصيِّر هذا المُكوِّن إمّا <code>‎<LoginButton /></code>‎ أو ‎<code><LogoutButton /></code>‎ بحسب حالته الحاليّة، سيُصيِّر أيضًا ‎<code><Greeting /></code>من المثال السّابق:<syntaxhighlight lang="javascript">
 +
class LoginControl extends React.Component {
 +
  constructor(props) {
 +
    super(props);
 +
    this.handleLoginClick = this.handleLoginClick.bind(this);
 +
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
 +
    this.state = {isLoggedIn: false};
 +
  }
 +
 
 +
  handleLoginClick() {
 +
    this.setState({isLoggedIn: true});
 +
  }
 +
 
 +
  handleLogoutClick() {
 +
    this.setState({isLoggedIn: false});
 +
  }
 +
 
 +
  render() {
 +
    const isLoggedIn = this.state.isLoggedIn;
 +
    let button;
 +
    if (isLoggedIn) {
 +
      button = <LogoutButton onClick={this.handleLogoutClick} />;
 +
    } else {
 +
      button = <LoginButton onClick={this.handleLoginClick} />;
 +
    }
 +
 
 +
    return (
 +
      <div>
 +
        <Greeting isLoggedIn={isLoggedIn} />
 +
        {button}
 +
      </div>
 +
    );
 +
  }
 +
}
 +
 
 +
ReactDOM.render(
 +
  <LoginControl />,
 +
  document.getElementById('root')
 +
);
 +
</syntaxhighlight>[https://codepen.io/gaearon/pen/QKzAgB?editors=0010 جرِّب المثال على موقع CodePen].
 +
 
 +
يُعدُّ تعريف متغير واستخدام جملة <code>if</code> طريقةً جيّدةً لتصيير المُكوِّن بشكلٍ شرطي، ولكن أحيانًا قد تريد استخدام صياغة مختصرة أكثر. هناك بعض الطرق لوضع الجمل الشرطية بشكل سطري (inline) في JSX سنشرحها الآن.
 +
 
 +
== جملة If السطرية مع المعامل المنطقي <code>&&</code> ==
 +
تستطيع تضمين [[React/introducing jsx|أي تعابير في JSX]] عن طريق تغليفها بين قوسين، يتضمن هذا المعامل المنطقي <code>&&</code> في JavaScript، حيث يكون مفيدا لتضمين عنصر بشكل شرطي:<syntaxhighlight lang="javascript">
 +
function Mailbox(props) {
 +
  const unreadMessages = props.unreadMessages;
 +
  return (
 +
    <div>
 +
      <h1>أهلًا!</h1>
 +
      {unreadMessages.length > 0 &&
 +
        <h2>
 +
          لديك {unreadMessages.length} رسائل غير مقروءة.
 +
        </h2>
 +
      }
 +
    </div>
 +
  );
 +
}
 +
 
 +
const messages = ['React', 'Re: React', 'Re:Re: React'];
 +
ReactDOM.render(
 +
  <Mailbox unreadMessages={messages} />,
 +
  document.getElementById('root')
 +
);
 +
 
 +
</syntaxhighlight>[https://codepen.io/gaearon/pen/ozJddz?editors=0010 جرب المثال على موقع CodePen].
 +
 
 +
يعمل هذا المثال بسبب تقييم التعبير <code>true && expression</code> إلى قيمة <code>expression</code> دومًا في JavaScript،  وتقييم التعبير <code>false && expression</code> دومًا إلى <code>false</code>. ولهذا إن كان الشرط صحيحًا (<code>true</code>) فسيظهر ضمن الناتج العنصر الموجود بعد المعامل <code>&&</code>، وإن كان الشرط خاطئًا (<code>false</code>) ستتجاهله React وتتخطاه.
 +
 
 +
لاحظ أنّ إعادة تعبير خاطئ (<code>false</code>) سيؤدي إلى تخطي العنصر الذي يلي<code>&&</code>، بيد أنّه سيعيد التعبير الخاطئ على أي حال. في المثال أدناه، سيُعاد <code><nowiki><div>0</div></nowiki></code> من قبل تابع التصيير <code>render</code>.<syntaxhighlight lang="javascript">
 +
render() {
 +
  const count = 0;
 +
  return (
 +
    <div>
 +
      { count && <h1>Messages: {count}</h1>}
 +
    </div>
 +
  );
 +
}
 +
</syntaxhighlight>
 +
 
 +
== جملة If-Else السطرية مع المعامل الشرطي ==
 +
من الطرق الأخرى المستخدمة للتصيير الشرطي بشكل سطري هي استخدام [[JavaScript/Conditional Operator|المعامل الشرطي الثلاثي]] في [[JavaScript]] وهو <code>condition ? true : false</code>‎.
 +
 
 +
سنستعمله في المثال التالي لنُصيِّر بشكل شرطي كتلة نصيّة صغيرة:<syntaxhighlight lang="javascript">
 +
render() {
 +
  const isLoggedIn = this.state.isLoggedIn;
 +
  return (
 +
    <div>
 +
      المستخدم <b>{isLoggedIn ? 'غير' : 'حاليًّا'}</b> مُسجِّل الدخول.
 +
    </div>
 +
  );
 +
}
 +
 
 +
 
 +
</syntaxhighlight>ويمكن استخدامه أيضًا للتعابير الأكبر رغم قلة وضوح ما الذي يحدث في هذا المثال:<syntaxhighlight lang="javascript">
 +
render() {
 +
  const isLoggedIn = this.state.isLoggedIn;
 +
  return (
 +
    <div>
 +
      {isLoggedIn ? (
 +
        <LogoutButton onClick={this.handleLogoutClick} />
 +
      ) : (
 +
        <LoginButton onClick={this.handleLoginClick} />
 +
      )}
 +
    </div>
 +
  );
 +
}
 +
 
 +
</syntaxhighlight>وكما هو الأمر في JavaScript فلك حرية اختيار التنسيق الملائم الذي تعتبره أنت وفريقك قابلًا للقراءة بشكلٍ أكبر. تذكّر دائمًا أنّه عندما تصبح الجمل الشرطية مُعقدة كثيرا فالأنسب هو [[React/components and props|استخراج المُكوِّن]].
 +
 
 +
== منع المكون من التصيير ==
 +
قد ترغب في حالات نادرة أن يُخفي المُكوِّن نفسه على الرّغم من أنّه قد صُيِّر بواسطة مُكوِّنٍ آخر، ولفعل ذلك أعد القيمة <code>null</code> بدلًا من الناتج المُصيَّر.
 +
 
 +
في المثال التالي يُصيَّر ‎<code><WarningBanner /></code>‎ اعتمادًا على قيمة الخاصيّة التي تُدعى <code>warn</code>، فإن كانت قيمتها <code>false</code> فلن يُصيَّر المُكوِّن:<syntaxhighlight lang="javascript">
 +
function WarningBanner(props) {
 +
  if (!props.warn) {
 +
    return null;
 +
  }
 +
 
 +
  return (
 +
    <div className="warning">
 +
      تحذير!
 +
    </div>
 +
  );
 +
}
 +
 
 +
class Page extends React.Component {
 +
  constructor(props) {
 +
    super(props);
 +
    this.state = {showWarning: true};
 +
    this.handleToggleClick = this.handleToggleClick.bind(this);
 +
  }
 +
 
 +
  handleToggleClick() {
 +
    this.setState(state => ({
 +
      showWarning: !state.showWarning
 +
    }));
 +
  }
 +
 
 +
  render() {
 +
    return (
 +
      <div>
 +
        <WarningBanner warn={this.state.showWarning} />
 +
        <button onClick={this.handleToggleClick}>
 +
          {this.state.showWarning ? 'Hide' : 'Show'}
 +
        </button>
 +
      </div>
 +
    );
 +
  }
 +
}
 +
 
 +
ReactDOM.render(
 +
  <Page />,
 +
  document.getElementById('root')
 +
);
 +
</syntaxhighlight>[https://codepen.io/gaearon/pen/Xjoqwm?editors=0010 جرب المثال على موقع CodePen].
 +
 
 +
لا تُؤثِّر إعادة <code>null</code> من التابع <code>render</code> الخاص بالمُكوِّن على إطلاق توابع دورة حياة المُكوِّن، فمثلًا لن يتأثر استدعاء التابع <code>componentDidUpdate</code>.
 +
== انظر أيضًا ==
 +
* [[React/hello world|مثال أهلًا بالعالم في React]]
 +
* [[React/introducing jsx|مقدمة إلى JSX]]
 +
* [[React/rendering elements|تصيير العناصر]]
 +
* [[React/components and props|المكونات والخاصيات]]
 +
* [[React/state and lifecycle|حالة ودورة حياة المكونات]]
 +
* [[React/handling events|معالجة الأحداث في React]]
 +
* [[React/lists and keys|القوائم والمفاتيح]]
 +
* [[React/forms|الحقول]]
 +
* [[React/lifting state up|رفع الحالات المشتركة للمستوى الأعلى]]
 +
* [[React/composition vs inheritance|الفرق بين التركيب والوراثة في React]]
 +
* [[React/thinking in react|أسلوب التفكير في React]]
 +
 
 +
== مصادر ==
 +
* [https://reactjs.org/docs/conditional-rendering.html صفحة التصيير الشرطي في توثيق React الرسمي].
 +
[[تصنيف:React]]
 +
[[تصنيف:React Main Concepts]]

المراجعة الحالية بتاريخ 15:58، 2 نوفمبر 2020

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

يعمل التصيير الشرطي (Conditional rendering) في React بنفس الطريقة التي تعمل فيها التعابير الشرطيّة في JavaScript، حيث تستطيع استخدام مُعامِلات JavaScript مثل if أو المُعامِل الشرطي لإنشاء عناصر تُمثِّل الحالة الحاليّة، ثمّ تدع React تُحدِّث واجهة المستخدم لمُطابقتها.

فلننظر إلى هذين المُكوِّنين:

function UserGreeting(props) {
  return <h1>أهلًا بعودتك!</h1>;
}

function GuestGreeting(props) {
  return <h1>يرجى التسجيل في الموقع</h1>;
}

سنُنشِئ مُكوِّن الترحيب Greeting الذي يعرض واحدًا من هذين المُكوِّنين بحسب حالة المستخدم إن كان قيد تسجيل الدخول أم لا:

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  // جرب التغيير إلى isLoggedIn={true}
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);

جرِّب المثال على موقع CodePen.

يعرض هذا المثال ترحيبًا مختلفًا اعتمادًا على قيمة الخاصيّة isLoggedIn.

متغيرات العناصر

بإمكانك استخدام المتغيّرات لتخزين العناصر، يُساعد هذا على تصيير جزء من المُكوِّن بشكل شرطي بحيث لا تتغير بقية ناتجه.

فلنأخذ هذين المُكوِّنين الجديدين اللذين يُمثِّلان أزرار تسجيل الخروج (Logout) وتسجيل الدخول (Login):

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      تسجيل الدخول
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      تسجيل الخروج
    </button>
  );
}

في المثال السّابق سنُنشِئ مُكوِّن له حالة وسنُسمّيه LoginControl. سيُصيِّر هذا المُكوِّن إمّا ‎<LoginButton />‎ أو ‎<LogoutButton />‎ بحسب حالته الحاليّة، سيُصيِّر أيضًا ‎<Greeting />‎ من المثال السّابق:

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

جرِّب المثال على موقع CodePen.

يُعدُّ تعريف متغير واستخدام جملة if طريقةً جيّدةً لتصيير المُكوِّن بشكلٍ شرطي، ولكن أحيانًا قد تريد استخدام صياغة مختصرة أكثر. هناك بعض الطرق لوضع الجمل الشرطية بشكل سطري (inline) في JSX سنشرحها الآن.

جملة If السطرية مع المعامل المنطقي &&

تستطيع تضمين أي تعابير في JSX عن طريق تغليفها بين قوسين، يتضمن هذا المعامل المنطقي && في JavaScript، حيث يكون مفيدا لتضمين عنصر بشكل شرطي:

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>أهلًا!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          لديك {unreadMessages.length} رسائل غير مقروءة.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

جرب المثال على موقع CodePen.

يعمل هذا المثال بسبب تقييم التعبير true && expression إلى قيمة expression دومًا في JavaScript،  وتقييم التعبير false && expression دومًا إلى false. ولهذا إن كان الشرط صحيحًا (true) فسيظهر ضمن الناتج العنصر الموجود بعد المعامل &&، وإن كان الشرط خاطئًا (false) ستتجاهله React وتتخطاه.

لاحظ أنّ إعادة تعبير خاطئ (false) سيؤدي إلى تخطي العنصر الذي يلي&&، بيد أنّه سيعيد التعبير الخاطئ على أي حال. في المثال أدناه، سيُعاد <div>0</div> من قبل تابع التصيير render.

render() {
  const count = 0;
  return (
    <div>
      { count && <h1>Messages: {count}</h1>}
    </div>
  );
}

جملة If-Else السطرية مع المعامل الشرطي

من الطرق الأخرى المستخدمة للتصيير الشرطي بشكل سطري هي استخدام المعامل الشرطي الثلاثي في JavaScript وهو condition ? true : false‎.

سنستعمله في المثال التالي لنُصيِّر بشكل شرطي كتلة نصيّة صغيرة:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      المستخدم <b>{isLoggedIn ? 'غير' : 'حاليًّا'}</b> مُسجِّل الدخول.
    </div>
  );
}

ويمكن استخدامه أيضًا للتعابير الأكبر رغم قلة وضوح ما الذي يحدث في هذا المثال:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

وكما هو الأمر في JavaScript فلك حرية اختيار التنسيق الملائم الذي تعتبره أنت وفريقك قابلًا للقراءة بشكلٍ أكبر. تذكّر دائمًا أنّه عندما تصبح الجمل الشرطية مُعقدة كثيرا فالأنسب هو استخراج المُكوِّن.

منع المكون من التصيير

قد ترغب في حالات نادرة أن يُخفي المُكوِّن نفسه على الرّغم من أنّه قد صُيِّر بواسطة مُكوِّنٍ آخر، ولفعل ذلك أعد القيمة null بدلًا من الناتج المُصيَّر.

في المثال التالي يُصيَّر ‎<WarningBanner />‎ اعتمادًا على قيمة الخاصيّة التي تُدعى warn، فإن كانت قيمتها false فلن يُصيَّر المُكوِّن:

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      تحذير!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);

جرب المثال على موقع CodePen.

لا تُؤثِّر إعادة null من التابع render الخاص بالمُكوِّن على إطلاق توابع دورة حياة المُكوِّن، فمثلًا لن يتأثر استدعاء التابع componentDidUpdate.

انظر أيضًا

مصادر