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


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


В React отрисовка по условию работает также, как и условия в JavaScript. Используйте условные операторы JavaScript, такие как if или тернарный оператор, чтобы создавать элементы, представляющие текущее состояние. Затем позвольте React обновить 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.




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

Пусть у нас есть камин с двумя кнопками управления. Кнопки представим в виде компонентов 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, рассмотрим их ниже.




Вы можете встраивать любые выражения в 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 пропустит его.




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

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


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

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


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

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




В редких случаях вам нужно, чтобы компонент себя скрыл, даже если он был отрисован другим компонентом. Чтобы это сделать, нужно вернуть 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.