Wie kann man bedingte Elemente haben und mit JSX von Facebook React trocken bleiben?

229

Wie füge ich optional ein Element in JSX ein? Hier ist ein Beispiel für die Verwendung eines Banners, das sich in der Komponente befinden sollte, wenn es übergeben wurde. Ich möchte vermeiden, dass HTML-Tags in der if-Anweisung dupliziert werden müssen.

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>
    );
}
Jack Allan
quelle
3
Was ist, wenn Sie keine elseFiliale haben ? Funktioniert das? Ich bin nicht vertraut mit jsx ...
Tom Fenech
1
Schön, das hat geholfen. Siehe auch github.com/facebook/react/issues/690
Gabriel Florit
Vollständige Liste der Optionen für das bedingte Rendern in React: robinwieruch.de/conditional-rendering-react
Robin Wieruch

Antworten:

151

Lassen Sie das Banner einfach als undefiniert und es wird nicht aufgenommen.

Jack Allan
quelle
1
Ich kann mir nichts anderes als Müll neben dieser Antwort
vorstellen
Funktioniert nullgenauso gut wie undefined? Ist das auch ein Teil der Spezifikation, dass es so funktioniert und daher in Zukunft wahrscheinlich nicht kaputt geht?
Hippietrail
133

Was ist damit? Definieren wir eine einfache Hilfskomponente If.

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

Und benutze es so:

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

UPDATE: Da meine Antwort immer beliebter wird, fühle ich mich verpflichtet, Sie vor der größten Gefahr im Zusammenhang mit dieser Lösung zu warnen. Wie in einer anderen Antwort ausgeführt, wird der Code in der <If />Komponente immer ausgeführt, unabhängig davon, ob die Bedingung wahr oder falsch ist. Daher schlägt das folgende Beispiel fehl, falls dies der Fall bannerist null(beachten Sie den Eigenschaftszugriff in der zweiten Zeile):

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

Sie müssen vorsichtig sein, wenn Sie es verwenden. Ich schlage vor, andere Antworten für alternative (sicherere) Ansätze zu lesen.

UPDATE 2: Rückblickend ist dieser Ansatz nicht nur gefährlich, sondern auch äußerst umständlich. Es ist ein typisches Beispiel dafür, wie ein Entwickler (ich) versucht, Muster und Ansätze, die er kennt, von einem Bereich in einen anderen zu übertragen, aber es funktioniert nicht wirklich (in diesem Fall in anderen Vorlagensprachen).

Wenn Sie ein bedingtes Element benötigen, gehen Sie folgendermaßen vor:

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

Wenn Sie auch den Zweig else benötigen, verwenden Sie einfach einen ternären Operator:

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

Es ist viel kürzer, eleganter und sicherer. Ich benutze es die ganze Zeit. Der einzige Nachteil ist, dass Sie nicht so einfach else ifverzweigen können, aber das ist normalerweise nicht so häufig.

Dies ist jedoch möglich, da logische Operatoren in JavaScript funktionieren. Die logischen Operatoren erlauben sogar kleine Tricks wie diesen:

<h3>{this.state.banner.title || 'Default banner title'}</h3>
tobik
quelle
1
Vielen Dank. Ich empfehle, diesen Artikel zu lesen. Github.com/facebook/react/issues/690 Dieser Link wurde in den Kommentaren unter dieser Frage veröffentlicht und ich habe ihn bemerkt, nachdem ich meine Lösung veröffentlicht hatte. Wenn Sie es überprüfen, erwähnt ein Typ diese Lösung ebenfalls, empfiehlt sie jedoch nicht. Ich persönlich denke, dass es in Ordnung ist, zumindest im Fall des OP, aber es ist wahr, dass dieser Weg nicht perfekt ist (es gibt keinen guten Weg, zum Beispiel einen anderen Zweig zu definieren). Auf jeden Fall lohnt es sich zu lesen.
Tobik
1
Ich ReactElement
bin
Wickeln Sie es einfach mit einem anderen Element ein, <span>oder <div>.
Tobik
Es gab ein Problem, als ich versuchte, damit <td> oder leer in <table> zu rendern, da <noscript> als untergeordnetes Element für <tr> nicht akzeptabel ist. Ansonsten funktioniert es gut für mich.
Green Su
1
Wenn Sie dies tun werden, gibt es eine transpilation Methode , die ziemlich gut: npmjs.com/package/jsx-control-statements
steve
82

Persönlich denke ich wirklich, dass die in ( JSX In Depth ) gezeigten ternären Ausdrücke die natürlichste Art sind, die den ReactJs-Standards entspricht.

Siehe folgendes Beispiel. Es ist auf den ersten Blick etwas chaotisch, funktioniert aber recht gut.

<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>
Chiedo
quelle
Hinweis: Die Klammern entsprechen einer Komponentenrückgabe, daher muss Ihr Inhalt von einem <div> </ div> umgeben sein.
JoeTidee
@Chiedo warum bevorzugst du stattdessen die beliebte Antwort? Das scheint großartig zu funktionieren.
Schneemann
2
@moby Ich denke, die beliebte Antwort ist dynamischer und führt zu einer saubereren Renderfunktion. Was passiert bei diesem Ansatz, wenn Sie mehrere Bedingungen haben? Sie haben jetzt den Wahnsinn, mit diesem seltsamen Format zu verschachteln, und wenn zwei separate Bereiche die gleichen Änderungen basierend auf der Bedingung benötigen, müssen Sie die Bedingung jetzt erneut schreiben. Nur meine Meinung! :)
Chiedo
Eine verwandte Seite ist auch sehr nützlich: facebook.github.io/react/docs/…
Neil
46

Sie können es auch wie schreiben

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

Wenn Ihr state.bannerist nulloder undefined, ist die rechte Seite der Bedingung übersprungenen.

wialy
quelle
41

Die IfStilkomponente ist gefährlich, da der Codeblock unabhängig von der Bedingung immer ausgeführt wird. Zum Beispiel würde dies eine Null - Ausnahme verursachen , wenn bannerist 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>
  );
}

Eine andere Option ist die Verwendung einer Inline-Funktion (besonders nützlich bei else-Anweisungen):

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

Eine weitere Option, um Probleme zu lösen :

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>
  );
}
Bendytree
quelle
2
Von allen bisherigen Lösungen scheint die Inline-Funktion die eleganteste und direkteste zu sein. Was sollte man beachten?
Suryasankar
22

&& + Code-Stil + kleine Komponenten

Diese einfache Testsyntax + Konvention im Codestil + kleine fokussierte Komponenten ist für mich die am besten lesbare Option da draußen. Sie brauchen nur spezielle Pflege von falsy Werte zu übernehmen möchten false, 0oder "".

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

Notation machen

Die Notationssyntax für ES7 Stage-0 ist ebenfalls sehr gut und ich werde sie definitiv verwenden, wenn meine IDE sie korrekt unterstützt:

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

Weitere Details hier: ReactJs - Erstellen einer "Wenn" -Komponente ... eine gute Idee?

Sebastien Lorber
quelle
Kostenlose nicht-grundlegende Informationen: Die erste heißtshort-circuit syntax
sospedra
1
@Deerloper Ich denke, der Unterschied zwischen && und & ist eines der ersten Dinge, die wir an Computerschulen lernen, aber einige Leute wissen es vielleicht nicht, daher ist es keine schlechte Idee, weitere Erklärungen zu geben: en.wikipedia.org/wiki/Short-circuit_evaluation
Sebastien Lorber
Stimmt, aber sie lehren es als Teil der klassischen bedingten Aussagen. Ich habe viele Leute verwirrt über die Verwendung des Kurzschlusses zum Rendern einer React-Komponente gefunden;)
sospedra
22

Einfach, erstellen Sie eine Funktion.

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

Diesem Muster folge ich persönlich die ganze Zeit. Macht Code wirklich sauber und leicht verständlich. Darüber hinaus können Sie Bannerdie eigene Komponente umgestalten, wenn sie zu groß wird (oder an anderen Stellen wiederverwendet wird).

Michael Yagudaev
quelle
13

Die experimentelle ES7- doSyntax macht dies einfach. Wenn Sie Babel verwenden, aktivieren Sie die es7.doExpressionsFunktion wie folgt:

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

Siehe http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions

Balexand
quelle
11

Wie bereits in den Antworten erwähnt, bietet Ihnen JSX zwei Optionen

  • Ternärer Operator

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

  • Logische Verbindung

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


Diese funktionieren jedoch nicht price == 0 .

JSX rendert im ersten Fall den falschen Zweig und im Falle einer logischen Verbindung wird nichts gerendert. Wenn die Eigenschaft 0 sein kann, verwenden Sie einfach if-Anweisungen außerhalb Ihrer JSX.

Lyubomir
quelle
Das ist kein JSX-Problem. Es ist die Bedingung selbst, selbst in einfachen JS würde sich das gleiche verhalten. Wenn Sie eine beliebige Nummer möchten, verwenden Sie diese einfach typeof(this.state.price) === "number"als Bedingung (in beiden Varianten).
Kroltan
8

Diese Komponente funktioniert, wenn sich mehr als ein Element im Zweig "if" befindet:

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

Verwendung:

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

Ps jemand denkt, dass diese Komponenten nicht gut zum Lesen von Code sind. Aber in meinen Augen ist HTML mit Javascript schlimmer

k.makarov
quelle
Wie bei der If-Antwort hier wird die falsche Bedingung weiterhin ausgeführt, obwohl sie nicht angezeigt wird.
Keegan 82
3

Die meisten Beispiele sind mit einer Zeile "HTML", die bedingt gerendert wird. Dies scheint für mich lesbar zu sein, wenn ich mehrere Zeilen habe, die bedingt gerendert werden müssen.

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

Erstes Beispiel ist gut, weil statt null wir einige andere Inhalte wie bedingt rendern können{this.props.showContent ? content : otherContent}

Wenn Sie jedoch nur Inhalte ein- / ausblenden müssen, ist dies sogar noch besser, da Boolesche Werte, Null und Undefiniert ignoriert werden

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>
  );
}
ivn
quelle
2

Es gibt eine andere Lösung, wenn Komponente für 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>
    );
}
Gordon Freeman
quelle
2

Ich verwende eine explizitere Verknüpfung: Ein sofort aufgerufener Funktionsausdruck (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})}/>
  }
})()}
jsdario
quelle
1

Ich habe https://www.npmjs.com/package/jsx-control-statements erstellt , um es ein bisschen einfacher zu machen. Im Grunde können Sie <If>Bedingungen als Tags definieren und sie dann in ternäre ifs kompilieren, damit der Code in den <If>nur erhalten wird ausgeführt, wenn die Bedingung erfüllt ist.

Alex Gilleran
quelle
1

Es gibt auch eine wirklich saubere einzeilige Version ... {this.props.product.title || "Kein Titel" }

Dh:

render: function() {
            return (
                <div className="title">
                    { this.props.product.title || "No Title" }
                </div>
            );
        }
max kaplan
quelle
Funktioniert das mit meinem obigen Beispiel? Wo sollte das Banner Div nicht erscheinen, wenn es keine Banner Requisite gibt?
Jack Allan
1

Ich habe kürzlich https://github.com/ajwhite/render-if erstellt , um Elemente nur dann sicher zu rendern, wenn das Prädikat erfolgreich ist .

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

oder

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

//...

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

Sie können Elemente mit dem ternären Operator wie folgt bedingt einschließen:

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>
}
mada-g
quelle
1

Sie können eine Funktion verwenden und die Komponente zurückgeben und die Renderfunktion dünn halten

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 />
    }
  }
}
pedronalbert
quelle
1

Hier ist mein Ansatz mit 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'));

Demo: http://jsfiddle.net/kb3gN/16688/

Ich verwende Code wie:

{opened && <SomeElement />}

Das wird SomeElementnur gerendert , wenn openedes wahr ist. Es funktioniert aufgrund der Art und Weise, wie JavaScript logische Bedingungen auflöst:

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

Wie Reactich ignorieren werde false, finde ich es sehr gut, einige Elemente bedingt zu rendern.

pie6k
quelle
1

Vielleicht hilft es jemandem, der auf die Frage stößt: Alle bedingten Renderings reagieren Es ist ein Artikel über die verschiedenen Optionen für das bedingte Rendern in React.

Wichtige Erkenntnisse darüber, wann welches bedingte Rendering verwendet werden soll:

** ansonsten

  • ist das grundlegendste bedingte Rendern
  • Anfänger freundlich
  • Verwenden Sie if, um eine Rendermethode vorzeitig zu deaktivieren, indem Sie null zurückgeben

** ternärer Operator

  • Verwenden Sie es über einer if-else-Anweisung
  • es ist prägnanter als wenn-sonst

** logischer && Operator

  • Verwenden Sie diese Option, wenn eine Seite der ternären Operation null zurückgibt

** Schaltergehäuse

  • ausführlich
  • kann nur mit selbstaufrufender Funktion eingefügt werden
  • Vermeiden Sie es, verwenden Sie stattdessen Aufzählungen

** Aufzählungen

  • Perfekt, um verschiedene Zustände abzubilden
  • Perfekt, um mehr als eine Bedingung abzubilden

** mehrstufige / verschachtelte bedingte Renderings

  • Vermeiden Sie sie aus Gründen der Lesbarkeit
  • Teilen Sie Komponenten mit ihrem eigenen einfachen bedingten Rendering in leichtere Komponenten auf
  • Verwenden Sie HOCs

** HOCs

  • Verwenden Sie sie, um bedingtes Rendern abzuschirmen
  • Komponenten können sich auf ihren Hauptzweck konzentrieren

** externe Vorlagenkomponenten

  • Vermeiden Sie sie und machen Sie sich mit JSX und JavaScript vertraut
Robin Wieruch
quelle
1

Mit ES6 können Sie dies mit einem einfachen Einzeiler tun

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

"show" ist ein Boolescher Wert und Sie verwenden diese Klasse von

<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>
Leon
quelle
1
Schlecht. Es wird immer berechnet.
Qwertiy
0

Ich glaube nicht, dass dies erwähnt wurde. Dies ist wie Ihre eigene Antwort, aber ich denke, es ist noch einfacher. Sie können jederzeit Zeichenfolgen aus den Ausdrücken zurückgeben und jsx in Ausdrücken verschachteln, sodass ein einfach zu lesender Inline-Ausdruck möglich ist.

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>

Juan Mendes
quelle
0

Ich mag die explizite Aussage von sofort aufgerufenen Funktionsausdrücken ( IIFE) und if-elseüber render callbacksund 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>
  );
}

Sie müssen sich nur mit der IIFESyntax vertraut machen , {expression}ist die übliche React-Syntax. Denken Sie nur daran, dass Sie eine Funktion schreiben, die sich selbst aufruft.

function() {

}()

das muss in parens eingewickelt werden

(function() {

}())
Gianluca Esposito
quelle
0

Es gibt auch eine Technik, bei der Render-Requisiten verwendet werden , um eine Komponente bedingt zu rendern. Der Vorteil ist, dass das Rendern erst ausgewertet wird, wenn die Bedingung erfüllt ist, sodass keine Sorgen um null und undefinierte Werte entstehen.

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>
        )}
      />
    )
  }
}
Farzad YZ
quelle
0

Wenn Sie nur etwas rendern müssen, wenn die übergebene Bedingung erfüllt ist, können Sie die folgende Syntax verwenden:

{ condition && what_to_render }

Der Code auf diese Weise würde folgendermaßen aussehen:

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

Es gibt natürlich auch andere gültige Möglichkeiten, dies zu tun. Es hängt alles von den Vorlieben und dem Anlass ab. Weitere Informationen zum bedingten Rendern in React finden Sie in diesem Artikel, wenn Sie interessiert sind.

Nesha Zoric
quelle
-1

Nur um eine weitere Option hinzuzufügen: Wenn Sie ein Kaffeeskript mögen / tolerieren, können Sie mit Coffee-React Ihre JSX schreiben. In diesem Fall können if / else-Anweisungen verwendet werden, da sie Ausdrücke im Kaffeeskript und keine Anweisungen sind:

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