Come avere elementi condizionati e mantenere ASCIUTTO con JSX di Facebook React?


229

Come posso includere facoltativamente un elemento in JSX? Ecco un esempio usando un banner che dovrebbe essere nel componente se è stato passato. Quello che voglio evitare è di duplicare i tag HTML nell'istruzione 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
E se non avessi un elseramo, funziona? Non ho familiarità con jsx ...
Tom Fenech,

1
Bello, questo ha aiutato. Vedi anche github.com/facebook/react/issues/690
Gabriel Florit,

elenco esaustivo di opzioni per eseguire il rendering condizionale in React: robinwieruch.de/conditional-rendering-react
Robin Wieruch

Risposte:


151

Lascia il banner come indefinito e non viene incluso.


1
Non riesco a pensare a nient'altro che spazzatura accanto a quella risposta ... come se mi fossi imbattuto negli dei
Timmerz,

Funziona nullaltrettanto bene undefined? Inoltre, quella parte delle specifiche funziona in questo modo e quindi probabilmente non si romperà in futuro?
hippietrail,

133

Che dire di questo. Definiamo un semplice Ifcomponente d' aiuto .

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

E usalo in questo modo:

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

AGGIORNAMENTO: Man mano che la mia risposta sta diventando popolare, mi sento in dovere di avvertirti del più grande pericolo legato a questa soluzione. Come sottolineato in un'altra risposta, il codice all'interno del <If />componente viene eseguito sempre indipendentemente dal fatto che la condizione sia vera o falsa. Pertanto il seguente esempio fallirà nel caso in cui bannersia null(notare l'accesso alla proprietà sulla seconda riga):

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

Devi stare attento quando lo usi. Suggerisco di leggere altre risposte per approcci alternativi (più sicuri).

AGGIORNAMENTO 2: Guardando indietro, questo approccio non è solo pericoloso ma anche disperatamente ingombrante. È un tipico esempio di quando uno sviluppatore (me) tenta di trasferire schemi e approcci che conosce da un'area all'altra ma in realtà non funziona (in questo caso altri linguaggi modello).

Se hai bisogno di un elemento condizionale, fallo in questo modo:

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

Se hai bisogno anche del ramo else, basta usare un operatore ternario:

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

È molto più corto, più elegante e sicuro. Io lo uso per tutto il tempo. L'unico svantaggio è che non puoi fare else iframificazioni così facilmente, ma di solito non è così comune.

Comunque, questo è possibile grazie al modo in cui funzionano gli operatori logici in JavaScript. Gli operatori logici consentono anche piccoli trucchi come questo:

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

1
Grazie. Consiglio di leggere questo github.com/facebook/react/issues/690 Questo link è stato pubblicato nei commenti sotto questa domanda e l'ho notato dopo aver pubblicato la mia soluzione. Se lo controlli, qualche ragazzo menziona anche questa soluzione ma non la consiglia. Personalmente penso che vada bene, almeno nel caso del PO, ma è vero che in questo modo non è perfetto (ad esempio non esiste un modo carino di definire il ramo di altro). Vale comunque la pena leggere.
Tobik,

1
Non sono sicuro che funzioni ancora perché l'ultima versione sembra richiedere che il valore restituito sia aReactElement
srph

Basta avvolgerlo con un altro elemento, <span>o <div>.
Tobik,

C'è un problema quando ho provato a usarlo per rendere <td> o vuoto in <table>, perché <noscript> non è accettabile come figlio per <tr>. Altrimenti funziona bene per me.
Green Su

1
Se hai intenzione di farlo, c'è un metodo di transpilation che è abbastanza buono: npmjs.com/package/jsx-control-statements
steve

82

Personalmente, penso davvero che le espressioni ternarie siano presenti in ( JSX In Depth ) siano il modo più naturale conforme agli standard ReactJs.

Vedi il seguente esempio. È un po 'disordinato a prima vista ma funziona abbastanza bene.

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

Nota: le parentesi sono le stesse del ritorno di un componente, quindi i tuoi contenuti devono essere racchiusi tra <div> </div>.
JoeTidee

@Chiedo perché preferisci invece la risposta popolare? Questo sembra funzionare alla grande.
Snowman,

2
@moby Penso che la risposta popolare sia più dinamica e si traduca in una funzione di rendering più pulita. Con questo approccio, cosa succede se si hanno più condizionali? Ora avrai una follia di nidificazione con questo strano formato e se due aree separate hanno bisogno delle stesse modifiche in base al condizionale, ora devi riscrivere nuovamente il condizionale. Solo la mia opinione però! :)
Chiedo,

è utile anche una pagina correlata: facebook.github.io/react/docs/…
Neil

46

Puoi anche scriverlo come

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

Se il tuo state.bannerè nullo undefined, il lato destro della condizione viene ignorato.


41

Il Ifcomponente di stile è pericoloso perché il blocco di codice viene sempre eseguito indipendentemente dalla condizione. Ad esempio, ciò provocherebbe un'eccezione nulla se 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>
  );
}

Un'altra opzione è quella di utilizzare una funzione incorporata (particolarmente utile con le istruzioni 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>
  );
}

Un'altra opzione dai problemi di reazione :

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
Di tutte le soluzioni finora, la funzione in linea sembra la più elegante e semplice. Qualcosa a cui bisogna fare attenzione?
suryasankar,

22

&& + stile codice + piccoli componenti

Questa semplice sintassi di prova + convenzione in stile codice + piccoli componenti focalizzati è per me l'opzione più leggibile in circolazione. Devi solo prestare particolare attenzione ai valori falsi come false, 0o "".

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

fare notazione

Anche la sintassi di notazione ES7 stage-0 è molto bella e la userò definitivamente quando il mio IDE lo supporta correttamente:

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

Maggiori dettagli qui: ReactJs - Creazione di un componente "If" ... una buona idea?


Informazioni non di base gratuite: il primo si chiamashort-circuit syntax
sospedra

1
@Deerloper Immagino che la differenza tra && e & sia una delle prime cose che impariamo nelle scuole di computer, ma alcune persone potrebbero non saperlo, quindi non è una cattiva idea dare ulteriori spiegazioni: en.wikipedia.org/wiki/Short-circuit_evaluation
Sebastien Lorber,

È vero, ma lo insegnano come parte delle classiche dichiarazioni condizionali. Ho trovato molte persone confuse sull'uso del cortocircuito per rendere un componente React;)
sospedra

22

Semplice, crea una funzione.

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

Questo è uno schema che seguo personalmente tutto il tempo. Rende il codice davvero pulito e di facile comprensione. Inoltre, ti consente di refactoring Bannernel suo componente se diventa troppo grande (o riutilizzato in altri luoghi).



11

Come già accennato nelle risposte, JSX ti offre due opzioni

  • Operatore ternario

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

  • Congiunzione logica

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


Tuttavia, quelli non funzionano price == 0 .

JSX renderà il ramo falso nel primo caso e in caso di congiunzione logica, nulla verrà reso. Se la proprietà può essere 0, basta usare if istruzioni al di fuori di JSX.


Non è un problema di JSX. È la condizione stessa, anche in pianura JS si comporterebbe lo stesso. Se vuoi un numero qualsiasi, basta usare typeof(this.state.price) === "number"come condizione (in entrambe le varianti).
Kroltan,

8

Questo componente funziona quando hai più di un elemento all'interno del ramo "if":

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

Uso:

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 qualcuno pensa che questi componenti non siano buoni per la lettura del codice. Ma nella mia mente, HTML con JavaScript è peggio


Come la risposta If qui, questo eseguirà comunque la falsa condizione anche se non viene visualizzata.
Keegan 82,

3

La maggior parte degli esempi sono con una riga di "html" che è resa in modo condizionale. Questo mi sembra leggibile quando ho più righe che devono essere rese condizionatamente.

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

Il primo esempio è buono perché invece di nullnoi possiamo rendere condizionalmente alcuni altri contenuti come{this.props.showContent ? content : otherContent}

Ma se hai solo bisogno di mostrare / nascondere i contenuti, questo è ancora meglio poiché i booleani, i valori null e quelli indefiniti sono ignorati

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

Esiste un'altra soluzione, se componente per 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>
    );
}

2

Uso un collegamento più esplicito: un'espressione di funzione immediatamente invocata (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

Esiste anche una versione a una riga davvero pulita ... {this.props.product.title || "Senza titolo" }

Vale a dire:

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

Funziona con il mio esempio sopra? Dove il banner div non dovrebbe apparire se non c'è il banner prop?
Jack Allan,

1

Di recente ho creato https://github.com/ajwhite/render-if per eseguire il rendering sicuro degli elementi solo se il predicato passa .

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

o

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

//...

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

1

È possibile includere condizionalmente elementi utilizzando l'operatore ternario in questo modo:

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

È possibile utilizzare una funzione e restituire il componente e mantenere sottile la funzione di rendering

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

Ecco il mio approccio con 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/

Sto usando un codice come:

{opened && <SomeElement />}

Ciò renderà SomeElementsolo se openedè vero. Funziona a causa del modo in cui JavaScript risolve le condizioni logiche:

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

Come Reactignorerò false, trovo che sia un ottimo modo per rendere condizionatamente alcuni elementi.


1

Forse aiuta qualcuno che incontra la domanda: tutti i rendering condizionali in React È un articolo su tutte le diverse opzioni per il rendering condizionale in React.

Key takeaway di quando utilizzare quale rendering condizionale:

** se altro

  • è il rendering condizionale più semplice
  • amichevole per principianti
  • utilizzare if per annullare anticipatamente un metodo di rendering restituendo null

** operatore ternario

  • usalo su un'istruzione if-else
  • è più conciso di if-else

** operatore logico &&

  • usalo quando un lato dell'operazione ternaria restituisce null

** scatola dell'interruttore

  • verboso
  • può essere integrato solo con la funzione auto-invocante
  • evitatelo, usate invece enums

** enums

  • perfetto per mappare stati diversi
  • perfetto per mappare più di una condizione

** rendering condizionali multilivello / nidificati

  • evitarli per motivi di leggibilità
  • suddividere i componenti in componenti più leggeri con il loro semplice rendering condizionale
  • usare HOC

** HOC

  • usali per proteggere il rendering condizionale
  • i componenti possono concentrarsi sul loro scopo principale

** componenti di templating esterni

  • evitali e mettiti comodo con JSX e JavaScript

1

Con ES6 puoi farlo con una semplice fodera

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

"show" è un valore booleano e usi questa classe per

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

1
Male. Sarà sempre calcolato.
Qwertiy,

0

Non credo sia stato menzionato. Questa è come la tua risposta, ma penso che sia ancora più semplice. Puoi sempre restituire stringhe dalle espressioni e annidare jsx all'interno delle espressioni, in modo da consentire un'espressione incorporata di facile lettura.

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

Mi piace l'esplicitazione delle espressioni di funzione invocate immediatamente ( IIFE) e if-elseancora render callbackse ancora 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>
  );
}

Hai solo bisogno di conoscere la IIFEsintassi, {expression}è la solita sintassi di React, al suo interno considera solo che stai scrivendo una funzione che sta invocando se stessa.

function() {

}()

che devono essere avvolti dentro le parentesi

(function() {

}())

0

Esiste anche una tecnica che utilizza i puntelli di rendering per eseguire il rendering condizionale di un componente. Il vantaggio è che il rendering non valuterà fino a quando non viene soddisfatta la condizione, senza preoccuparsi di valori nulli e indefiniti .

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

Quando è necessario eseguire il rendering di qualcosa solo se la condizione passata è piena, è possibile utilizzare la sintassi:

{ condition && what_to_render }

Il codice in questo modo sarebbe simile al seguente:

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

Esistono, naturalmente, altri modi validi per farlo, dipende tutto dalle preferenze e dall'occasione. Puoi imparare altri modi su come eseguire il rendering condizionale in React in questo articolo se sei interessato!


-1

Solo per aggiungere un'altra opzione - se ti piace / tollerare lo script del caffè puoi usare coffee-reazioni per scrivere il tuo JSX nel qual caso le istruzioni / else sono utilizzabili in quanto sono espressioni nello script del caffè e non nelle istruzioni:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.