Jak mieć elementy warunkowe i zachować SUSZENIE dzięki JSX Facebook React?

229

Jak opcjonalnie dołączyć element do JSX? Oto przykład użycia banera, który powinien znajdować się w elemencie, jeśli został przekazany. Chcę uniknąć duplikowania tagów HTML w instrukcji 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>
    );
}
Jack Allan
źródło
3
Co, jeśli po prostu nie masz elseoddziału, czy to działa? Nie znam jsx ...
Tom Fenech
1
Fajnie, to pomogło. Zobacz także github.com/facebook/react/issues/690
Gabriel Florit
wyczerpująca lista opcji renderowania warunkowego w React: robinwieruch.de/conditional-rendering-react
Robin Wieruch

Odpowiedzi:

151

Po prostu zostaw baner jako niezdefiniowany i nie zostanie uwzględniony.

Jack Allan
źródło
1
Nie mogę wymyślić nic oprócz śmieci obok tej odpowiedzi ... tak, jakbym natknął się na bogów
Timmerz
Czy nulldziała równie dobrze jak undefined? Czy jest to także część specyfikacji, która działa w ten sposób, a zatem prawdopodobnie nie pęknie w przyszłości?
hippietrail
133

A co z tym. Zdefiniujmy prosty Ifkomponent pomocniczy .

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

I użyj tego w ten sposób:

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

AKTUALIZACJA: Ponieważ moja odpowiedź staje się popularna, czuję się zobowiązany do ostrzeżenia cię przed największym niebezpieczeństwem związanym z tym rozwiązaniem. Jak wskazano w innej odpowiedzi, kod wewnątrz <If />komponentu jest wykonywany zawsze, niezależnie od tego, czy warunek jest prawdziwy, czy fałszywy. Dlatego poniższy przykład zawiedzie w przypadku, gdy bannerjest null(zwróć uwagę na dostęp do właściwości w drugim wierszu):

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

Musisz zachować ostrożność podczas korzystania z niego. Sugeruję przeczytanie innych odpowiedzi dla alternatywnych (bezpieczniejszych) podejść.

AKTUALIZACJA 2: Patrząc wstecz, takie podejście jest nie tylko niebezpieczne, ale także wyjątkowo kłopotliwe. Jest to typowy przykład sytuacji, gdy programista (ja) próbuje przenieść wzorce i podejścia, które zna z jednego obszaru do drugiego, ale tak naprawdę to nie działa (w tym przypadku inne języki szablonów).

Jeśli potrzebujesz elementu warunkowego, zrób to w ten sposób:

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

Jeśli potrzebujesz również gałęzi else, po prostu użyj operatora trójskładnikowego:

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

Jest o wiele krótszy, bardziej elegancki i bezpieczny. Używam tego cały czas. Jedyną wadą jest to, że nie można tak else ifłatwo rozgałęziać, ale zwykle nie jest to tak powszechne.

W każdym razie jest to możliwe dzięki działaniu operatorów logicznych w JavaScript. Operatory logiczne dopuszczają nawet takie małe sztuczki:

<h3>{this.state.banner.title || 'Default banner title'}</h3>
tobik
źródło
1
Dzięki. Polecam przeczytanie tego github.com/facebook/react/issues/690 Ten link został opublikowany w komentarzach poniżej tego pytania i zauważyłem go po opublikowaniu mojego rozwiązania. Jeśli to sprawdzisz, jakiś facet również wspomina o tym rozwiązaniu, ale go nie zaleca. Osobiście uważam, że jest w porządku, przynajmniej w przypadku PO, ale to prawda, że ​​ten sposób nie jest idealny (na przykład nie ma fajnego sposobu zdefiniowania innej gałęzi). W każdym razie warto przeczytać.
tobik
1
Nie jestem pewien, czy to nadal działa, ponieważ wydaje się, że najnowsza wersja wymaga, aby zwracana wartość wynosiła aReactElement
srph
Wystarczy owinąć go innym elementem <span>lub <div>.
tobik
Występuje problem, gdy próbowałem użyć tego do renderowania <td> lub pustego w <table>, ponieważ <noscript> jest niedopuszczalny jako element podrzędny dla <tr>. W przeciwnym razie działa dla mnie dobrze.
Green Su
1
Jeśli masz zamiar to zrobić, istnieje całkiem dobra metoda transpilacji
Steve
82

Osobiście uważam, że wyrażenia trójskładnikowe w ( JSX In Depth ) są najbardziej naturalnym sposobem, który jest zgodny ze standardami ReactJs.

Zobacz następujący przykład. Na pierwszy rzut oka jest trochę niechlujny, ale działa całkiem dobrze.

<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
źródło
Uwaga: nawiasy kwadratowe są takie same jak zwrot komponentu, więc twoja treść musi być otoczona przez <div> </div>.
JoeTidee
@Chiedo, dlaczego zamiast tego wolisz popularną odpowiedź? To wydaje się działać świetnie.
Bałwan
2
@moby Myślę, że popularna odpowiedź jest bardziej dynamiczna i skutkuje czystszą funkcją renderowania. Przy takim podejściu co się stanie, jeśli masz wiele warunków warunkowych? Będziesz teraz miał obłęd zagnieżdżania się w tym dziwnym formacie i jeśli dwa oddzielne obszary wymagają tych samych zmian w zależności od warunku, musisz teraz ponownie napisać warunek. Ale tylko moja opinia! :)
Chiedo
powiązana strona jest również bardzo przydatna: facebook.github.io/react/docs/…
Neil
46

Możesz też tak napisać

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

Jeśli state.bannerjest nulllub undefined, po prawej stronie od warunku zostanie pominięty.

Wialy
źródło
41

Składnik Ifstylu jest niebezpieczny, ponieważ blok kodu jest zawsze wykonywany niezależnie od warunku. Na przykład spowoduje to wyjątek zerowy, jeśli bannerjest 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>
  );
}

Inną opcją jest użycie funkcji wbudowanej (szczególnie przydatnej w przypadku instrukcji 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>
  );
}

Kolejna opcja reagowania na problemy :

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
źródło
2
Ze wszystkich dotychczasowych rozwiązań funkcja wbudowana wydaje się najbardziej elegancka i prosta. Coś, na co należy uważać?
suryasankar
22

&& + w stylu kodu + małe komponenty

Ta prosta składnia testu + konwencja w stylu kodu + małe skoncentrowane komponenty są dla mnie najbardziej czytelną opcją. Po prostu trzeba zachować szczególną ostrożność wartości falsy podoba false, 0albo "".

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

notacja

Składnia notacji ES7 na etapie 0 jest również bardzo przyjemna i definitywnie użyję jej, gdy moje IDE poprawnie ją obsługuje:

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

Więcej informacji tutaj: ReactJs - Tworzenie komponentu „Jeśli”… dobry pomysł?

Sebastien Lorber
źródło
Bezpłatne nie-podstawowe informacje: pierwsza nazywa sięshort-circuit syntax
sospedra
1
@Deerloper Myślę, że różnica między && i & jest jedną z pierwszych rzeczy, których uczymy się w szkołach komputerowych, ale niektórzy ludzie mogą nie wiedzieć, więc nie jest złym pomysłem, aby podać więcej wyjaśnień: en.wikipedia.org/wiki/Short-circuit_evaluation
Sebastien Lorber
To prawda, ale uczą tego w ramach klasycznych instrukcji warunkowych. Znalazłem wielu ludzi zdezorientowanych używaniem zwarcia do renderowania składnika React;)
sospedra
22

Proste, utwórz funkcję.

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

Jest to wzór, który osobiście cały czas stosuję. Sprawia, że ​​kod jest naprawdę czysty i łatwy do zrozumienia. Co więcej, pozwala on na refaktoryzację Bannerdo własnego komponentu, jeśli staje się zbyt duży (lub ponownie używany w innych miejscach).

Michael Yagudaev
źródło
13

Eksperymentalna doskładnia ES7 ułatwia to. Jeśli używasz Babel, włącz tę es7.doExpressionsfunkcję, a następnie:

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

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

Balexand
źródło
11

Jak już wspomniano w odpowiedziach, JSX oferuje dwie opcje

  • Operator trójskładnikowy

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

  • Logiczna koniunkcja

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


Jednak te nie działają price == 0 .

JSX wyrenderuje fałszywą gałąź w pierwszym przypadku, aw przypadku logicznej koniunkcji nic nie będzie renderowane. Jeśli właściwość może wynosić 0, po prostu użyj instrukcji if poza twoim JSX.

Lyubomir
źródło
To nie jest problem z JSX. Jest to sam warunek, nawet po prostu JS zachowałby się tak samo. Jeśli chcesz dowolną liczbę, po prostu użyj typeof(this.state.price) === "number"jako warunek (w dowolnym wariancie).
Kroltan
8

Ten komponent działa, gdy masz więcej niż jeden element w gałęzi „if”:

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

Stosowanie:

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 ktoś myśli, że te składniki nie są dobre do odczytu kodu. Ale moim zdaniem HTML z javascript jest gorszy

k.makarov
źródło
Podobnie jak w przypadku odpowiedzi „tutaj”, spowoduje to wykonanie warunku fałszywego, nawet jeśli nie zostanie wyświetlony.
Keegan 82
3

Większość przykładów zawiera jeden wiersz „html”, który jest renderowany warunkowo. Wydaje mi się to czytelne, gdy mam wiele wierszy, które muszą być renderowane warunkowo.

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

Pierwszy przykład jest dobry, ponieważ zamiast tego nullmożemy warunkowo renderować inne treści, takie jak{this.props.showContent ? content : otherContent}

Ale jeśli chcesz tylko pokazać / ukryć zawartość, jest to jeszcze lepsze, ponieważ booleany, zero i niezdefiniowane są ignorowane

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
źródło
2

Istnieje inne rozwiązanie, jeśli komponent 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
źródło
2

Używam bardziej wyraźnego skrótu: Wyrażenie funkcji natychmiast wywołane (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
źródło
1

Zrobiłem https://www.npmjs.com/package/jsx-control-statements zrobić to nieco łatwiej, w zasadzie to pozwala na definiowanie <If>warunkowe jako znaczniki, a następnie zestawia je w trójskładnikowych IFS tak, że kod wewnątrz <If>tylko dostaje wykonywane, jeśli warunek jest spełniony.

Alex Gilleran
źródło
1

Istnieje również naprawdę czysta wersja jednoliniowa ... {this.props.product.title || "Bez tytułu" }

To znaczy:

render: function() {
            return (
                <div className="title">
                    { this.props.product.title || "No Title" }
                </div>
            );
        }
max kaplan
źródło
Czy to działa z moją próbką powyżej? Gdzie div banner nie powinien się pojawiać, jeśli nie ma propozycji bannera?
Jack Allan,
1

Ostatnio zrobiłem https://github.com/ajwhite/render-if, aby bezpiecznie renderować elementy tylko wtedy, gdy predykat przejdzie .

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

lub

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

//...

{ifUniverseIsWorking(
  <span>Hello!</span>
)}
Atticus
źródło
1

Możesz warunkowo dołączyć elementy za pomocą operatora trójskładnikowego w następujący sposób:

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
źródło
1

Możesz użyć funkcji i zwrócić komponent oraz zachować cienką funkcję renderowania

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
źródło
1

Oto moje podejście przy użyciu 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/

Używam kodu takiego jak:

{opened && <SomeElement />}

Uczyni to SomeElementtylko wtedy, gdy openedbędzie to prawdą. Działa ze względu na sposób, w jaki JavaScript rozwiązuje warunki logiczne:

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

Jak Reactto zignoruję false, uważam, że jest to bardzo dobry sposób warunkowego renderowania niektórych elementów.

pie6k
źródło
1

Może pomaga komuś, kto zada pytanie: Wszystkie renderowania warunkowe w React To artykuł o wszystkich różnych opcjach renderowania warunkowego w React.

Kluczowe informacje na temat tego, kiedy użyć renderowania warunkowego:

** Jeśli inaczej

  • jest najbardziej podstawowym renderowaniem warunkowym
  • przyjazny dla początkujących
  • użyj if, aby wcześniej zrezygnować z metody renderowania, zwracając null

** operator trójskładnikowy

  • użyj go zamiast instrukcji if-else
  • jest bardziej zwięzły niż gdyby-inaczej

** operator logiczny i&

  • użyj go, gdy jedna strona operacji trójskładnikowej zwróci wartość null

** Sprawa przełącznik

  • gadatliwy
  • można wstawiać tylko za pomocą funkcji samowywołania
  • unikaj, zamiast tego używaj wyliczeń

** śliwki

  • idealny do mapowania różnych stanów
  • idealny do mapowania więcej niż jednego warunku

** wielopoziomowe / zagnieżdżone renderingi warunkowe

  • unikaj ich ze względu na czytelność
  • dzielić komponenty na bardziej lekkie komponenty z ich własnym prostym renderowaniem warunkowym
  • używaj HOC

** HOC

  • użyj ich, aby ukryć renderowanie warunkowe
  • komponenty mogą koncentrować się na ich głównym celu

** zewnętrzne elementy szablonów

  • unikaj ich i bądź wygodny z JSX i JavaScript
Robin Wieruch
źródło
1

Za pomocą ES6 możesz to zrobić za pomocą prostej liniówki

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

„show” to boolean i używasz tej klasy przez

<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>
Leon
źródło
1
Zły. To będzie zawsze obliczone.
Qwertiy
0

Nie sądzę, żeby o tym wspomniano. To twoja odpowiedź, ale myślę, że jest jeszcze prostsza. Zawsze możesz zwrócić ciągi z wyrażeń i możesz zagnieździć jsx wewnątrz wyrażeń, więc pozwala to na łatwe do odczytania wyrażenie wbudowane.

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
źródło
0

Podoba mi się jawność natychmiastowych wywołań wyrażeń funkcyjnych ( IIFE) i if-elsepowyżej render callbacksoraz 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>
  );
}

Musisz tylko zapoznać się ze IIFEskładnią, {expression}jest to zwykła składnia React, wewnątrz niej po prostu weź pod uwagę, że piszesz funkcję, która się wywołuje.

function() {

}()

które muszą być owinięte w pareny

(function() {

}())
Gianluca Esposito
źródło
0

Istnieje również technika wykorzystująca rekwizyty renderujące do warunkowego renderowania komponentu. Zaletą jest to, że renderowanie nie będzie oceniać, dopóki warunek nie zostanie spełniony, co nie powoduje obaw o wartości zerowe i niezdefiniowane .

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
źródło
0

Gdy musisz renderować tylko coś, jeśli spełniony warunek jest spełniony, możesz użyć składni:

{ condition && what_to_render }

Kod w ten sposób wyglądałby następująco:

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

Istnieją oczywiście inne ważne sposoby, aby to zrobić, wszystko zależy od preferencji i okazji. Możesz dowiedzieć się więcej na temat sposobu renderowania warunkowego w React w tym artykule, jeśli jesteś zainteresowany!

Nesha Zoric
źródło
-1

Wystarczy dodać kolejną opcję - jeśli podoba Ci się / toleruje skrypt kawy, możesz użyć polecenia coffee-reag, aby napisać swój JSX, w którym to przypadku, jeśli instrukcje / else są użyteczne, ponieważ są wyrażeniami w skrypcie kawy, a nie instrukcjami:

render: ->
  <div className="container">
    {
      if something
        <h2>Coffeescript is magic!</h2>
      else
        <h2>Coffeescript sucks!</h2>
    }
  </div>  
Hal
źródło
-1

Wystarczy rozszerzyć odpowiedź @Jack Allan o odniesienia do dokumentów.

nullW takim przypadku sugerowana jest reakcja na podstawową dokumentację (Szybki start) . Jednak wartości logiczne, zerowe i niezdefiniowane są również ignorowane , o czym wspomniano w przewodniku dla zaawansowanych.

Oleg V.
źródło
Poprawione w celu wyjaśnienia - fałszywe, zerowe, niezdefiniowane i prawdziwe są również ważne do zignorowania - facebook.github.io/react/docs/… . Chociaż w Szybkim Startu wolą nie odpowiadać.
Oleg V.