2.8 Отрисовка по условию

В React вы можете создавать определенные компоненты, которые инкапсулируют то поведение, которое вам необходимо. Затем вы можете отрисовывать только некоторые из них, в зависимости от состояния вашего приложения.

Отрисовка по условию в React работает тем же образом, как и условия в JavaScript. Используйте JavaScript операторы, такие как if или тернарный опрератор, чтобы создавать элементы, представляющие текущее состояние, и позвольте React обновить UI чтобы привести их(состояние и UI) в соответствие.

Рассмотрим два компонента:

Код
        
  function ErrorMessage(props) {
    return <h3>Произошла ошибка на сервере. Не удалось сохранить ваши данные.</h3>;
  }

  function SuccessMessage(props) {
    return <h3>Ваши данные успешно сохранены!</h3>;
  }
    

Мы создадим компонент Response, который отображает каждый из этих компонентов, в зависимости от результата сохранения данных на сервере:

Код
        
  function Response(props) {
    const isSuccess = props.isSuccess;
    if (isSuccess) {
      return <SuccessMessage/>;
    }
    return <ErrorMessage/>;
    //или
    //return isSuccess ? <SuccessMessage/> : <ErrorMessage/>
  }
  // Можете поменять на isSuccess={false}:
  ReactDOM.render(<Response isSuccess={true} />,  document.getElementById('root'));
    

Посмотреть в CodePen

Этот пример отрисовывает сообщения в зависимости от значения свойства isSuccess.


2.8.1 Хранение элементов в переменных

Вы можете использовать переменные, чтобы хранить элементы. Это может помочь вам отрисовывать по условию часть компонента, в то время как оставшаяся часть результата вывода не изменится.

Пусть у нас есть камин. Рассмотрим два компонента, представляющие его SetFire и SnuffOut кнопки:

Код
        
  function SetFireButton(props) {
    return (<button className="orange" onClick={props.onClick}>Зажечь</button>);
  }

  function SnuffOutButton(props) {
    return (<button className="blue" onClick={props.onClick}>Потушить</button>);
  }
    

В примере ниже, мы создадим компонент с состоянием, под названием FirePlace.

Он будет отрисовывать либо <SetFireButton /> либо <SnuffOutButton /> в зависимости от его текущего состояния. Также он будет отрисовывать компонент <Indicator />, показывающий сообщения о состоянии нашего камина:

Код
        
  class FirePlace extends React.Component {
    constructor(props) {
      super(props);
      this.onSetFire = this.onSetFire.bind(this);
      this.onSnuffOut = this.onSnuffOut.bind(this);
      this.state = {isBurning: false};
    }

    onSetFire() {
      this.setState({isBurning: true});
    }

    onSnuffOut() {
      this.setState({isBurning: false});
    }

    render() {
      const isBurning = this.state.isBurning;

      let button = null;
      if(isBurning){
        button = <SnuffOutButton onClick={this.onSnuffOut} />
      } else {
        button = <SetFireButton onClick={this.onSetFire} />;
      }
      return (
        <div>
          <Indicator isBurning={isBurning} />
          {button}
        </div>
      );
    }
  }
    

Посмотреть в CodePen

В то время как объявление переменной и использование if оператора – хороший способ отрисовывать компонент по условию, иногда вы можете хотеть использовать более короткий синтаксис. Есть несколько способов встроить условия в JSX, рассматриваемые ниже.


2.8.2 Встроенный If с логическим оператором &&

Вы можете встраивать любые выражения в JSX, оборачивая их в фигурные скобки. Это включает в себя и логический && оператор JavaScript. Это может быть удобно для добавления элемента по условию:

Код
        
  function Console(props) {
    const errors = props.errors;
    return (
      <p>
        <h3>Attention!</h3>
        {errors.length > 0 &&
          <p>You have <b>{errors.length}</b> errors.</p>
        }
      </p>
    );
  }

  const errors = [
  'Failed to load resource: net::ERR_INSECURE_RESPONSE',
  'TypeError: e is undefined',
  'Uncaught ReferenceError: calculate is not defined'
  ];
  ReactDOM.render(<Console errors={errors} />, document.getElementById('root'));
    

Это работает, потому что в JavaScript true && выражение всегда возвращает выражение, а false && выражение всегда возвращает false.

Следовательно, если условие истинно, элемент появится в результате вывода прямо после &&. Если условие ложно, React проигнорирует и пропустит его.


2.8.3 Встраивание If-else с помощью условного оператора

Другим методом встраиваемой отрисовки элементов по условию является использование тернарного оператора JavaScript: условие ? true : false

В примере ниже мы используем его для отрисовки по условию маленького блока текста:

Код
        
  render() {
    const isSent = this.state.isSent;
    return (
      <p>
        <h3>Ваше сообщение {isSent ? 'успешно' : 'не'} отправлено</h3>
      </p>
    );
  }
    

Это может быть полезно для более длинных выражений, даже если менее очевидно что в нем происходит:

Код
        
  render() {
    const isNew = this.state.isNew;
    return (
      <p>
        {isNew ? (<EditButton onClick={this.onEdit} /> <DeleteButton onClick={this.onDelete} />)
                  : (<AddButton onClick={this.onAdd} />)}
      </p>
    );
  }
    

Как и в JavaScript, выбор подходящего стиля, основанного на том, что вы и ваша команда видит наиболее читабельным, остается за вами. Также помните, что как только условия становятся очень сложными, возможно наступило отличное время выделить компонент .


2.8.4 Предотвращение отрисовки компонента

В редких случаях вы можете захотеть, чтобы компонент скрыл себя, даже если он был отрисован другим компонентом. Чтобы это сделать, нужно вернуть null, вместо его результата отрисовки.

В примере ниже, <DangerAlert /> отрисовывается, в зависимости от значения переменной isDangerAlertShowed в состоянии. Если её значение равно false, то компонент не отрисовывается:

Код
        
  function DangerAlert(props) {
    return (
      <h3 className="alert alert-danger">{props.text}</h3>
    );
  }

  class Application extends React.Component {
    constructor(props) {
      super(props);
      this.state = {isDangerAlertShowed: true}
      this.toggleDangerAlert = this.toggleDangerAlert.bind(this);
    }

    toggleDangerAlert() {
      this.setState(prevState => ({
        isDangerAlertShowed: !prevState.isDangerAlertShowed
      }));
    }

    render() {
      return (
        <div>
          {this.state.isDangerAlertShowed ?
              <DangerAlert text={'Внимание! В приложении возникли некоторые проблемы!'} /> : null}
          <button onClick={this.toggleDangerAlert}>
            {this.state.isDangerAlertShowed ? 'Скрыть' : 'Показать'}
          </button>
        </div>
      );
    }
  }

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

Посмотреть в CodePen

Возвращение null из метода render компонента не влияет на срабатывание методов жизненного цикла компонента. К примеру, componentWillUpdate и componentDidUpdate по прежнему будут вызываться.