Як мати умовні елементи та підтримувати DRY за допомогою JSX Facebook React?


229

Як я можу додатково включити елемент у JSX? Ось приклад використання банера, який повинен бути в компоненті, якщо він був переданий. Я хочу уникати того, щоб дублювати теги HTML в операторі if.

render: function () {
    var banner;
    if (this.state.banner) {
        banner = <div id="banner">{this.state.banner}</div>;
    } else {
        banner = ?????
    }
    return (
        <div id="page">
            {banner}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

3
Що робити, якщо у вас просто немає elseфілії, це працює? Я не знайомий з jsx ...
Том Фенек,

1
Приємно, це допомогло. Також дивіться github.com/facebook/react/isissue/690
Габріель Флорит

вичерпний перелік варіантів здійснення умовного візуалізації в React: robinwieruch.de/conditional-rendering-react
Робін Вірух

Відповіді:


151

Просто залиште банер не визначеним, і він не буде включений.


1
Я не можу придумати нічого, окрім сміття поруч із цією відповіддю ... так, ніби я натрапив на богів
Тіммерц

Чи nullпрацює так само добре undefined? Також є та частина специфікації, що вона працює таким чином і, таким чином, не може зламатись у майбутньому?
hippietrail

133

Як що до цього. Давайте визначимо простий Ifкомпонент допомоги .

var If = React.createClass({
    render: function() {
        if (this.props.test) {
            return this.props.children;
        }
        else {
            return false;
        }
    }
});

І використовувати це так:

render: function () {
    return (
        <div id="page">
            <If test={this.state.banner}>
                <div id="banner">{this.state.banner}</div>
            </If>
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

ОНОВЛЕННЯ: Оскільки моя відповідь стає популярною, я відчуваю, що я зобов’язаний попередити вас про найбільшу небезпеку, пов'язану з цим рішенням. Як вказувалося в іншій відповіді, код всередині <If />компонента виконується завжди незалежно від того, чи умова істинна чи помилкова. Тому наступний приклад не вдасться у випадку, якщо bannerє null(зверніть увагу на доступ до властивостей у другому рядку):

<If test={this.state.banner}>
    <div id="banner">{this.state.banner.url}</div>
</If>

Ви повинні бути обережними, коли ним користуєтесь. Я пропоную прочитати інші відповіді щодо альтернативних (безпечніших) підходів.

ОНОВЛЕННЯ 2: Озираючись назад, цей підхід є не лише небезпечним, але й відчайдушно громіздким. Це типовий приклад того, коли розробник (я) намагається передати шаблони та підходи, які він знає, з однієї області в іншу, але це насправді не працює (в цьому випадку інші мови шаблонів).

Якщо вам потрібен умовний елемент, зробіть це так:

render: function () {
    return (
        <div id="page">
            {this.state.banner &&
                <div id="banner">{this.state.banner}</div>}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

Якщо вам також потрібна інша галузь, просто скористайтеся потрійним оператором:

{this.state.banner ?
   <div id="banner">{this.state.banner}</div> :
   <div>There is no banner!</div>
}

Це коротше, елегантніше та безпечніше. Я ним користуюся постійно. Єдиним недоліком є ​​те, що ви не можете виконати else ifрозгалуження так легко, але зазвичай це не так часто.

У будь-якому випадку це можливо завдяки тому, як працюють логічні оператори в JavaScript. Логічні оператори навіть дозволяють такі маленькі хитрощі:

<h3>{this.state.banner.title || 'Default banner title'}</h3>

1
Дякую. Я рекомендую прочитати це github.com/facebook/react/isissue/690 Це посилання було розміщено в коментарях нижче цього питання, і я помітив його після того, як опублікував своє рішення. Якщо ви перевірите це, хтось хлопець згадує і про це рішення, але не рекомендує його. Я особисто думаю, що це нормально, принаймні у випадку з ОП, але це правда, що цей спосіб не є ідеальним (наприклад, немає жодного приємного способу визначити іншу галузь). У всякому разі, варто прочитати.
tobik

1
Не впевнений, чи все-таки це працює, оскільки, здається, остання версія вимагає, щоб повернене значення булоReactElement
srph

Просто обгорніть його іншим елементом, <span>або <div>.
tobik

Виникла проблема, коли я намагався використовувати це для відображення <td> або порожнього в <table>, тому що <noscript> не є прийнятним для дитини <tr>. Інакше для мене це добре працює.
Зелене су

1
Якщо ви збираєтеся це зробити, є досить хороший метод транспіляції
Стів

82

Особисто я думаю, що потрійні вирази, показані в ( JSX In Depth ), є найбільш природним способом, який відповідає стандартам ReactJs.

Дивіться наступний приклад. Це трохи безладно на перший погляд, але працює досить добре.

<div id="page">
  {this.state.banner ? (
    <div id="banner">
     <div class="another-div">
       {this.state.banner}
     </div>
    </div>
  ) : 
  null} 
  <div id="other-content">
    blah blah blah...
  </div>
</div>

Примітка: дужки збігаються з поверненням компонента, тому ваш вміст повинен бути оточений <div> </div>.
JoeTidee

@Chiedo чому ти віддаєш перевагу популярній відповіді? Це, здається, працює чудово.
Сніговик

2
@moby Я думаю, що популярна відповідь є більш динамічною і призводить до більш чистої функції візуалізації. При такому підході, що станеться, якщо у вас є кілька умов? Тепер у вас буде безумство вкладати цей дивний формат, і якщо двом окремим областям потрібні однакові зміни, що базуються на умовному, вам доведеться знову переписати умовне. Просто моя думка, хоча! :)
Chiedo

пов’язана сторінка також досить корисна: facebook.github.io/react/docs/…
Ніл

46

Ви також можете написати це так

{ this.state.banner && <div>{...}</div> }

Якщо ви state.bannerє nullабо undefined, права частина умови пропускається.


41

Компонент Ifстилю небезпечний тим, що блок коду завжди виконується незалежно від умови. Наприклад, це призведе до нульового виключення, якщо bannerє null:

//dangerous
render: function () {
  return (
    <div id="page">
      <If test={this.state.banner}>
        <img src={this.state.banner.src} />
      </If>
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

Інший варіант полягає у використанні вбудованої функції (особливо корисно для інших операторів):

render: function () {
  return (
    <div id="page">
      {function(){
        if (this.state.banner) {
          return <div id="banner">{this.state.banner}</div>
        }
      }.call(this)}
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

Ще один варіант реагування на проблеми :

render: function () {
  return (
    <div id="page">
      { this.state.banner &&
        <div id="banner">{this.state.banner}</div>
      }
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

2
З усіх рішень досі, вбудована функція виглядає найелегантнішою і прямої. На що слід стежити?
suryasankar

22

&& + стиль коду + невеликі компоненти

Цей простий синтаксис тесту + конвенція в стилі коду + невеликі орієнтовані компоненти - для мене найбільш читабельний варіант. Вам просто потрібно подбати про помилкові значення, наприклад false, 0або "".

render: function() {
    var person= ...; 
    var counter= ...; 
    return (
       <div className="component">
          {person && (
            <Person person={person}/>
          )}
          {(typeof counter !== 'undefined') && (
            <Counter value={counter}/>
          )}
       </div>
    );
}

робити позначення

Синтаксис позначення нотацій ES7 stage-0 також дуже приємний, і я остаточно буду використовувати його, коли мій IDE правильно його підтримує:

const Users = ({users}) => (
  <div>
    {users.map(user =>
      <User key={user.id} user={user}/>
    )}
  </div>
)  

const UserList = ({users}) => do {
  if (!users) <div>Loading</div>
  else if (!users.length) <div>Empty</div>
  else <Users users={users}/>
}

Детальніше тут: ReactJs - Створення компонента "If" ... хороша ідея?


Безкоштовна неосновна інформація: перша називаєтьсяshort-circuit syntax
sospedra

1
@Deerloper Я думаю, що різниця між && та & - це одне з перших речей, які ми дізнаємось у комп’ютерних школах, але деякі люди, можливо, не знають, тому давати більше пояснень не погано: en.wikipedia.org/wiki/Short-circuit_evaluation
Себастьєн Лорбер

Щоправда, але вони вчать це як частину класичних умовних висловлювань. Я знайшов багато людей, що плутаються з приводу використання короткого замикання для надання компонента React;)
sospedra

22

Просто, створити функцію.

renderBanner: function() {
  if (!this.state.banner) return;
  return (
    <div id="banner">{this.state.banner}</div>
  );
},

render: function () {
  return (
    <div id="page">
      {this.renderBanner()}
      <div id="other-content">
        blah blah blah...
      </div>
    </div>
  );
}

Це шаблон, якого я особисто дотримуюсь весь час. Робить код дійсно чистим і зрозумілим. Більше того, він дозволяє переробляти Bannerна свій власний компонент, якщо він стає занадто великим (або повторно використовується в інших місцях).


13

Експериментальний doсинтаксис ES7 робить це легко. Якщо ви використовуєте Babel, увімкніть цю es7.doExpressionsфункцію:

render() {
  return (
    <div id="banner">
      {do {
        if (this.state.banner) {
          this.state.banner;
        } else {
          "Something else";
        }
      }}
    </div>
  );
}

Дивіться http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions


11

Як вже було сказано у відповідях, JSX пропонує вам два варіанти

  • Термінальний оператор

    { this.state.price ? <div>{this.state.price}</div> : null }

  • Логічний сполучник

    { this.state.price && <div>{this.state.price}</div> }


Однак ті не працюють price == 0 .

JSX візуалізує помилкову гілку в першому випадку, а в разі логічного сполучення нічого не буде виведено. Якщо властивість може бути 0, просто використовуйте, якщо виписки за межами вашого JSX.


Це не проблема JSX. Це сама умова, навіть у звичайному JS поводився б так само. Якщо ви хочете будь-яке число, просто використовуйте typeof(this.state.price) === "number"як умову (в будь-якому варіанті).
Кролтан

8

Цей компонент працює, коли у вас є більше одного елемента всередині гілки "if":

var Display = React.createClass({
  render: function () {
    if (!this.props.when) {
      return false;
    }
    return React.DOM.div(null, this.props.children);
  },
});

Використання:

render: function() {
  return (
    <div>
      <Display when={this.state.loading}>
        Loading something...
        <div>Elem1</div>
        <div>Elem2</div>
      </Display>
      <Display when={!this.state.loading}>
        Loaded
        <div>Elem3</div>
        <div>Elem4</div>
      </Display>
    </div>
  );
}

Хтось вважає, що ці компоненти не корисні для читання коду. Але на мій погляд, Html з javascript - це гірше


Як і у випадку відповіді If, тут все одно буде виконуватися помилкова умова, хоча вона не відображається.
Кіган 82

3

Більшість прикладів - один рядок "html", який надається умовно. Мені це здається читабельним, коли у мене є кілька рядків, які потрібно візуалізувати умовно.

render: function() {
  // This will be renered only if showContent prop is true
  var content = 
    <div>
      <p>something here</p>
      <p>more here</p>
      <p>and more here</p>
    </div>;

  return (
    <div>
      <h1>Some title</h1>

      {this.props.showContent ? content : null}
    </div>
  );
}

Перший приклад хороший тим, що замість цього nullми можемо умовно надати якийсь інший контент, як-от{this.props.showContent ? content : otherContent}

Але якщо вам просто потрібно показати / приховати вміст, це ще краще, оскільки ігноруються булеві, нульові та невизначені

render: function() {
  return (
    <div>
      <h1>Some title</h1>

      // This will be renered only if showContent prop is true
      {this.props.showContent &&
        <div>
          <p>something here</p>
          <p>more here</p>
          <p>and more here</p>
        </div>
      }
    </div>
  );
}


2

Я використовую більш чіткий ярлик: Вираз негайного виклику функції (IIFE):

{(() => {
  if (isEmpty(routine.queries)) {
    return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
  } else if (this.state.configured) {
    return <DeviceList devices={devices} routine={routine} configure={() => this.setState({configured: false})}/>
  } else {
    return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
  }
})()}


1

Існує також дійсно чиста версія рядка ... {this.props.product.title || "Без назви"}

Тобто:

render: function() {
            return (
                <div className="title">
                    { this.props.product.title || "No Title" }
                </div>
            );
        }

Це працює з моїм зразком вище? Де банер діва не повинен з’являтися, якщо немає банерної опори?
Джек Аллан

1

Нещодавно я створив https://github.com/ajwhite/render-if, щоб безпечно відобразити елементи, лише якщо присудок проходить .

{renderIf(1 + 1 === 2)(
  <span>Hello!</span>
)}

або

const ifUniverseIsWorking = renderIf(1 + 1 === 2);

//...

{ifUniverseIsWorking(
  <span>Hello!</span>
)}

1

Ви можете умовно включати елементи, використовуючи термінальний оператор так:

render: function(){

         return <div id="page">

                  //conditional statement
                  {this.state.banner ? <div id="banner">{this.state.banner}</div> : null}

                  <div id="other-content">
                      blah blah blah...
                  </div>

               </div>
}

1

Ви можете використовувати функцію, повертати компонент і тонко виконувати функцію візуалізації

class App extends React.Component {
  constructor (props) {
    super(props);
    this._renderAppBar = this._renderAppBar.bind(this);
  }

  render () {
    return <div>
      {_renderAppBar()}

      <div>Content</div>

    </div>
  }

  _renderAppBar () {
    if (this.state.renderAppBar) {
      return <AppBar />
    }
  }
}

1

Ось мій підхід із використанням ES6.

import React, { Component } from 'react';
// you should use ReactDOM.render instad of React.renderComponent
import ReactDOM from 'react-dom';

class ToggleBox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // toggle box is closed initially
      opened: false,
    };
    // http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
    this.toggleBox = this.toggleBox.bind(this);
  }

  toggleBox() {
    // check if box is currently opened
    const { opened } = this.state;
    this.setState({
      // toggle value of `opened`
      opened: !opened,
    });
  }

  render() {
    const { title, children } = this.props;
    const { opened } = this.state;
    return (
      <div className="box">
        <div className="boxTitle" onClick={this.toggleBox}>
          {title}
        </div>
        {opened && children && (
          <div class="boxContent">
            {children}
          </div>
        )}
      </div>
    );
  }
}

ReactDOM.render((
  <ToggleBox title="Click me">
    <div>Some content</div>
  </ToggleBox>
), document.getElementById('app'));

Демо: http://jsfiddle.net/kb3gN/16688/

Я використовую код типу:

{opened && <SomeElement />}

Це відображається SomeElementлише в тому випадку, якщо openedце правда. Він працює через те, як JavaScript вирішує логічні умови:

true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if `opened` is true, will output false otherwise

Як Reactігнорувати false, я вважаю, що це дуже хороший спосіб умовно передати деякі елементи.


1

Можливо, це допомагає тому, хто стикається з питанням: Усі умовні візуалізації в реакті - це стаття про всі різні варіанти умовного відображення в React.

Основні заходи, коли використовувати умовне відображення:

** інше

  • є найбільш базовою умовною візуалізацією
  • для початківців
  • використовувати if для відмови від раннього методу візуалізації шляхом повернення null

** потрійний оператор

  • використовувати його над оператором if-else
  • вона більш лаконічна, ніж інша

** логічний &&оператор

  • використовувати його, коли одна сторона потрійної операції повернеться до нуля

** корпус комутатора

  • багатослівний
  • може бути накреслений лише функцією самовикликання
  • уникайте цього, використовуйте замість цього перерахунки

** перераховує

  • ідеально підходить для відображення різних станів
  • ідеально підходить для відображення декількох умов

** багаторівневі / вкладені умовні візуалізації

  • уникати їх заради читабельності
  • розділити компоненти на більш легкі компоненти з власним простим умовним відображенням
  • використовувати HOCs

** ГОС

  • використовувати їх для екранування умовного візуалізації
  • компоненти можуть зосередитись на своєму основному призначенні

** зовнішні компоненти шаблону

  • уникайте їх і будьте зручні з JSX та JavaScript

1

За допомогою ES6 ви можете зробити це за допомогою простого однолінійного

const If = ({children, show}) => show ? children : null

"show" - булевий, і ви використовуєте цей клас

<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>

1
Поганий. Це завжди буде обчислено.
Qwertiy

0

Я не думаю, що це вже згадувалося. Це як ваша відповідь, але я думаю, що це навіть простіше. Ви завжди можете повертати рядки з виразів і можете вкласти jsx всередині виразів, тому це дозволяє легко читати вбудовані вирази.

render: function () {
    return (
        <div id="page">
            {this.state.banner ? <div id="banner">{this.state.banner}</div> : ''}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpf1/t39.3284-6/10574688_1565081647062540_1607884640_n.js"></script>
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpa1/t39.3284-6/10541015_309770302547476_509859315_n.js"></script>
<script type="text/jsx;harmony=true">void function() { "use strict";

var Hello = React.createClass({
  render: function() {
    return (
      <div id="page">
        {this.props.banner ? <div id="banner">{this.props.banner}</div> : ''}
        <div id="other-content">
          blah blah blah...
        </div>
      </div>
    );   
  }
});

var element = <div><Hello /><Hello banner="banner"/></div>;
React.render(element, document.body);

}()</script>


0

Мені подобається чіткість функцій виразів негайно викликаних функцій ( IIFE) та if-elseнад render callbacksта ternary operators.

render() {
  return (
    <div id="page">
      {(() => (
        const { banner } = this.state;
        if (banner) {
          return (
            <div id="banner">{banner}</div>
          );
        }
        // Default
        return (
          <div>???</div>
        );
      ))()}
      <div id="other-content">
        blah blah blah...
      </div>
    </div>
  );
}

Вам просто потрібно ознайомитись із IIFEсинтаксисом, {expression}це звичайний синтаксис React, усередині нього просто врахуйте, що ви пишете функцію, яка викликає себе.

function() {

}()

які потрібно загорнути всередину паронів

(function() {

}())

0

Існує також техніка використання рендери для умовного візуалізації компонента. Ця перевага полягає в тому , що рендер НЕ буде оцінювати , поки умова не буде виконана, в результаті чтого не варто турбуватися за нуль і невизначених значень.

const Conditional = ({ condition, render }) => {
  if (condition) {
    return render();
  }
  return null;
};

class App extends React.Component {
  constructor() {
    super();
    this.state = { items: null }
  }

  componentWillMount() {
    setTimeout(() => { this.setState({ items: [1,2] }) }, 2000);
  }

  render() {
    return (
      <Conditional
        condition={!!this.state.items}
        render={() => (
          <div>
            {this.state.items.map(value => <p>{value}</p>)}
          </div>
        )}
      />
    )
  }
}

0

Якщо вам потрібно щось зробити лише якщо заповнений стан заповнений, ви можете використовувати синтаксис:

{ condition && what_to_render }

Код таким чином виглядатиме так:

render() {
    const { banner } = this.state;
    return (
        <div id="page">
            { banner && <div id="banner">{banner}</div> }
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

Звичайно, є й інші вагомі способи зробити це, все залежить від уподобань та випадків. Ви можете дізнатися більше способів зробити умовне візуалізацію в React в цій статті, якщо вам це цікаво!


-1

Просто додайте ще один варіант - якщо вам подобається / терплять кавовий скрипт, ви можете скористатися функцією кави-реакції, щоб написати свій JSX. У такому випадку, якщо / else заяви можна використовувати, оскільки вони є виразами у кавовому скрипті, а не у твердженнях:

render: ->
  <div className="container">
    {
      if something
        <h2>Coffeescript is magic!</h2>
      else
        <h2>Coffeescript sucks!</h2>
    }
  </div>  

-1

Просто для розширення відповіді @Jack Allan із посиланнями на документи.

nullУ такому випадку пропонується реагувати основна документація (Швидкий старт) . Однак ігноруються булеві, нульові та невизначені , про що йдеться в Додатковому посібнику.


Виправлені для уточнення - помилкові, недійсні, невизначені та істинні також можуть бути ігноровані - facebook.github.io/react/docs/… . Хоча, у Швидкому старті вони вважають за краще порадити нульовими.
Олег Вікторович
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.