رندر کردن شرطی

در ری اکت، شما می‌توانید کامپوننت‌های مجزایی بسازید که رفتار مورد نیاز شما را کپسوله سازی کنند. سپس می‌توانید فقط بعضی از این کامپوننت‌ها را بسته به state برنامه رندر کنید .

رندر کردن شرطی در ری‌اکت همان‌طور کار می‌کند که شرط‌ها در جاوا‌اسکریپت کار می‌کنند. از عملگرهای جاوااسکریپت مانند if یا عملگر شرطی (conditional operator) برای ساختن المنت‌هایی که نمایانگر state کنونی هستند، استفاده کنید و بگذارید ری‌اکت UI را به‌روز رسانی کند تا با آن‌ها منطبق شود.

این دو کامپوننت را در نظر بگیرید:

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</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 امتحان کنید

این مثال بر اساس مقدار prop با نام isLoggedIn یک [پیام] خوش‌آمد گویی متفاوتی را رندر می‌کند.

متغیر‌های المنت

شما می‌توانید از متغییرها برای ذخیره کردن المنت‌ها استفاده کنید. این به شما کمک می‌کند تا بتوانید بخشی از یک کامپوننت را به‌صورت شرطی، رندر کرده، درحالی‌که بقیه خروجی کامپوننت تغییری نمی‌کند.

این دو کامپوننت جدید را در نظر بگیرید که نمایانگر دکمه‌های ورود (Login) و خروج (Logout) هستند.

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

در مثال زیر، یک کامپوننت دارای state به نام LoginControl می‌سازیم.

این [کامپوننت] یا <LoginButton /> یا <LogoutButton /> را براساس state کنونی رندر خواهد کرد. همچنین، یک <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، یک روش خوب برای رندرکردن شرطی است؛ گاهی ممکن است شما بخواهید یک syntax کوتاه‌تر داشته باشید. چندین روش برای شرط های خطی در JSX وجود دارد که در زیر توضیح داده شده است:

if خطی با استفاده از عملگر منطقی &&

شما می‌توانید هر expression را در JSX به صورت توکار با قراردادن در آکولاد بنویسید. این مورد شامل عملگر منطقی && هم می‌شود. کاربرد آن برای اضافه‌کردن شرطی یک المنت است:

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

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

روی CodePen استفاده کنید

این روش جواب می‌دهد چرا که در جاوااسکریپت، حاصل true && expression همیشه برابر است با expression و همچنین حاصل false && expression ‍‍ همیشه برابر است با false.

بنابراین اگر شرط برابر با true باشد، المنتی که بلافاصله بعد از عملگر && قرار گرفته است در خروجی نمایش داده خواهد شد و اگر حاصل شرط برابر باfalse باشد،‌ ری‌اکت این عبارت را نادیده می‌گیرد.

if-else خطی با عملگر شرطی

روش دیگر رندر شرطی المنت‌ها به‌صورت خطی،‌ استفاده از عملگر شرطی جاوااسکریپت condition ? true : false است.

در مثال زیر ما از این روش استفاده می‌کنیم تا متن کوتاهی را به‌صورت شرطی رندر کنیم.

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

از این روش همچنین می‌توان برای عبارات شرطی طولانی‌تر استفاده نمود، اگرچه که در اینصورت کمتر مشخص است که [در کد نوشته شده] چه اتفاقی افتاده است:

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

درست مثل جاوااسکریپت، انتخاب اینکه کدام روش مناسب است، به نظر شما و تیم شما بستگی دارد که کدام روش برای شما خوانا‌تر است.‌ همچنین به یاد داشته باشید که هرگاه شرط‌ها بیش از اندازه پیچیده شدند،ممکن است زمان خوبی باشه که یک کامپوننت استخراج کنید.

جلوگیری از رندر شدن کامپوننت

در موارد نادر، ممکن است شما بخواهید یک کامپوننت - حتی اگر توسط یک کامپوننت دیگر رندر شده باشد - خودش را مخفی کند. برای انجام این کار، null را به‌جای خروجی رندر برگردانید.

در مثال زیر، کامپوننت <WarningBanner /> بر‌اساس مقدار prop ای به‌نام warn رندر می‌شود. اگر مقدار این prop برابر باfalse باشد، در این‌صورت این کامپوننت رندر نمی‌شود.

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

  return (
    <div className="warning">
      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 همچنان فراخوانی خواهد شد.