Как иметь условные элементы и сохранять СУХОЙ с JSX Facebook React?

216

Как мне добавить элемент в 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/issues/690
Показать ещё 1 комментарий
Теги:
react-jsx

25 ответов

144
Лучший ответ

Просто оставьте баннер undefined и он не включится.

  • 1
    Я не могу думать ни о чем, кроме мусора рядом с этим ответом ... как будто я наткнулся на богов
  • 0
    null работает так же хорошо, как и undefined ? Также это та часть спецификации, что она работает таким образом и, следовательно, вряд ли сломается в будущем?
Показать ещё 1 комментарий
130

Как насчет этого. Определите простой компонент 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>
  • 1
    Благодарю. Я рекомендую прочитать этот github.com/facebook/react/issues/690. Эта ссылка была опубликована в комментариях под этим вопросом, и я заметил это после того, как опубликовал свое решение. Если вы проверите это, какой-то парень тоже упоминает это решение, но не рекомендует его. Лично я думаю, что все в порядке, по крайней мере, в случае с OP, но это правда, что этот путь не идеален (нет хорошего способа определить другую ветку, например). Во всяком случае, стоит прочитать.
  • 1
    Не уверен, что это все еще работает, поскольку последняя версия, по-видимому, требует, чтобы возвращаемое значение было ReactElement
Показать ещё 8 комментариев
79

Лично я действительно думаю, что тройные выражения, показанные в 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>
  • 0
    Примечание: квадратные скобки совпадают с возвращаемым компонентом, поэтому ваш контент должен быть заключен в <div> </ div>.
  • 0
    @Chiedo, почему вы предпочитаете популярный ответ? Кажется, это отлично работает.
Показать ещё 2 комментария
40

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

Другой вариант - использовать встроенную функцию (особенно полезную для операторов 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>
  );
}

Еще один вариант из реакции issues:

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
    Пока что из всех решений встроенная функция выглядит самой элегантной и простой. Что-нибудь, что нужно остерегаться?
39

Вы также можете записать его как

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

Если ваш state.banner равен null или undefined, правая часть условия пропускается.

20

&& + code-style + small components

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

  • 0
    Бесплатная неосновная информация: первая называется short-circuit syntax
  • 1
    @Deerloper Я думаю, что разница между && и & является одной из первых вещей, которую мы изучаем в компьютерных школах, но некоторые люди могут не знать, поэтому не стоит придумывать больше объяснений: en.wikipedia.org/wiki/Short-circuit_evaluation
Показать ещё 1 комментарий
15

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

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

  • 0
    Вы только что спасли меня, спасибо человек
13

Экспериментальный синтаксис 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

12

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

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

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

  • Логическое соединение

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


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

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

  • 0
    Это не проблема 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>
            );
        },

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

  • 0
    Как и ответ «Если» здесь, он все равно будет выполнять ложное условие, даже если оно не отображается.
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}

Но если вам просто нужно показать/скрыть контент, это еще лучше, так как Булевы, 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>
  );
}
2

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

Есть другое решение, если компонент для 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>
    );
}
1

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

Ключевые выводы о том, когда использовать условный рендеринг:

** if-else

  • - это самый основной условный рендеринг
  • новичок дружелюбный
  • использовать, если раньше отказаться от метода рендеринга, вернув null

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

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

** logical && & Оператор

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

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

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

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

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

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

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

** HOCs

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

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

  • избегайте их и устраивайте JSX и JavaScript
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

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

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

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

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

или

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

//...

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

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

0

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

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

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

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

}()

которые должны быть обернуты внутри parens

(function() {

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

Существует также действительно чистая версия одной строки... {this.props.product.title || "Без названия" }

Т.е:

render: function() {
            return (
                <div className="title">
                    { this.props.product.title || "No Title" }
                </div>
            );
        }
  • 0
    Это работает с моим образцом выше? Где не должен появляться баннер div, если нет баннера реквизита?
-1

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

В этом случае рекомендуется базовая документация (Quick Start) null. Однако Booleans, Null и Undefined Игнорируются, упомянутые в Расширенном руководстве.

  • 0
    Исправлено, чтобы уточнить - false, null, undefined и true также могут быть проигнорированы - facebook.github.io/react/docs/… . Хотя, в Quick Start они предпочитают совет нуль.
-2

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню