Как иметь условные элементы и оставаться сухим с JSX Facebook React?

как дополнительно включить элемент в 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>
    );
}

27 ответов


просто оставьте баннер как неопределенный, и он не будет включен.


как насчет этого. Давайте определим простую помощь 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>
    );
}

Если Вам также нужна ветка else, просто используйте тернарный оператор:

{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>

лично я действительно думаю, что троичные выражения показывают в http://facebook.github.io/react/tips/if-else-in-JSX.html самый естественный путь который соответствует с стандартами 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>

вы также можете написать его как

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

если state.banner is null или undefined, пропущена правая сторона условия.


на If компонент стиля опасен, потому что блок кода всегда исполняются независимо от состояния. Например, это вызовет исключение null, если banner is 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>
  );
}

другой вариант-использовать встроенную функцию (особенно полезную для операторов else):

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>
  );
}

еще один вариант от react вопросы:

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>
  );
}

&& + код-стиль + небольшие компоненты

этот простой синтаксис теста + соглашение в стиле Кода + небольшие сфокусированные компоненты для меня самый читаемый вариант там. Вам просто нужно заботиться о фальшивых значениях, таких как 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}/>
}


просто создайте функцию.

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 в свой собственный компонент, если он становится слишком большим (или повторно используется в других местах).


экспериментальный ES7 do синтаксис делает это легко. Если вы используете 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


как уже упоминалось в ответах, JSX представляет вам два варианта

  • тернарный оператор

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

  • логическое

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


однако, те не работают для price == 0.

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


этот компонент работает, когда у вас есть более одного элемента внутри ветви "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>
            );
        },

P. s. кто-то думает, что эти компоненты не подходят для чтения кода. Но на мой взгляд html с javascript хуже


большинство примеров имеют одну строку "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}

но если вам просто нужно показать / скрыть контент, это еще лучше, так как логические значения, Null и Undefined игнорируются

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>
  );
}

есть другое решение,если компонент для React:

var Node = require('react-if-comp');
...
render: function() {
    return (
        <div id="page">
            <Node if={this.state.banner}
                  then={<div id="banner">{this.state.banner}</div>} />
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

Я использую более явный ярлык: немедленно вызываемое выражение функции (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})}/>
  }
})()}

Я сделал https://www.npmjs.com/package/jsx-control-statements чтобы сделать его немного проще, в основном это позволяет определить <If> условные обозначения в виде тегов, а затем компилирует их в троичные ifs, чтобы код внутри <If> выполняется, только если условие истинно.


есть также очень чистый line версия... { этот.реквизит.товар.title / / "нет Title"}

Ie:

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

Я сделал https://github.com/ajwhite/render-if недавно безопасно визуализировать элементы только если предикат передает.

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

или

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

//...

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

вы можете условно включать элементы, используя тернарный оператор, например:

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>
}

вы можете использовать функцию и вернуть компонент и сохранить тонкую функцию рендеринга

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 />
    }
  }
}

вот мой подход с использованием 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

As React игнорировать false, Я считаю, что это очень хороший способ условно отобразить некоторые элементы.


может быть, это поможет кому-то, кто сталкивается с вопросом: все условные визуализации в React это статья обо всех различных вариантах условного рендеринга в React.

Key takeaways когда использовать, какой условный рендеринг:

* * if-else

  • является самым основным условным рендерингом
  • для начинающих
  • используйте if для раннего отказа от метода рендеринга, вернувшись значение null

** тернарный оператор

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

** логический оператор&&

  • используйте его, когда одна сторона троичной операции вернет null

** корпус переключателя

  • подробное
  • может быть встроен только с функцией самостоятельного вызова
  • избегайте его, используйте перечисления вместо

** перечисления

  • идеально подходит для отображения различных состояний
  • идеально подходит для отображения более одного условия

* * многоуровневые / вложенные условные визуализации

  • избегайте их ради удобочитаемости
  • разделить компоненты на более легкие компоненты с их собственным простым условным рендерингом
  • использовать HOCs

** HOCs

  • используйте их для защиты от условного рендеринга
  • компоненты могут сосредоточиться на своей основной цели

** внешние компоненты шаблонов

  • избегайте их и будьте удобны с JSX и JavaScript

С ES6 вы можете сделать это с помощью простого однострочного

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

"show" является логическим, и вы используете этот класс по

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

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

мне нравится эксплицитность немедленно вызываемых выражений функций (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() {

}()

что нужно обернуть внутри parens

(function() {

}())

существует также метод, с помощью отображения реквизит для условного отображения компонента. Это преимущество заключается в том, что рендер не будет оценивать, пока условие не будет выполнено, в результате чего не беспокойтесь за null и неопределено значения.

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>
        )}
      />
    )
  }
}

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

{ 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 in в этой статье если вам интересно!


просто добавить еще один вариант-если вам нравится / терпеть кофе-скрипт, вы можете использовать кофе-реагировать, чтобы написать свой JSX, и в этом случае, если / else операторы могут использоваться как выражения в кофе-скрипте, а не операторы:

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

просто расширить @Jack Allan ответ со ссылками на документы.

React basic (быстрый запуск) документация предлагает null в таком случае. Однако,логические значения, Null и Undefined игнорируются а также, упомянутый в расширенном руководстве.