Bagaimana cara memiliki elemen bersyarat dan tetap KERING dengan JSX Facebook React?


229

Bagaimana saya secara opsional memasukkan elemen dalam JSX? Berikut ini adalah contoh menggunakan spanduk yang seharusnya ada di komponen jika sudah disahkan. Yang ingin saya hindari adalah harus menduplikasi tag HTML dalam pernyataan 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
Bagaimana jika Anda tidak memiliki elsecabang, apakah itu berhasil? Saya tidak terbiasa dengan jsx ...
Tom Fenech

1
Bagus, ini membantu. Lihat juga github.com/facebook/react/issues/690
Gabriel Florit

daftar lengkap opsi untuk melakukan rendering bersyarat di Bereaksi: robinwieruch.de/conditional-rendering-react
Robin Wieruch

Jawaban:


151

Biarkan saja banner tidak terdefinisi dan tidak disertakan.


1
Saya tidak bisa memikirkan apa pun kecuali sampah di sebelah jawaban itu ... seolah-olah saya menemukan para dewa
Timmerz

Apakah nullberfungsi sama baiknya undefined? Apakah bagian dari spek itu bekerja dengan cara ini dan dengan demikian tidak akan pecah di masa depan?
hippietrail

133

Bagaimana dengan ini. Mari kita mendefinisikan Ifkomponen bantuan sederhana .

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

Dan gunakan seperti ini:

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: Karena jawaban saya semakin populer, saya merasa berkewajiban untuk memperingatkan Anda tentang bahaya terbesar yang terkait dengan solusi ini. Seperti yang ditunjukkan dalam jawaban lain, kode di dalam <If />komponen dieksekusi selalu terlepas dari apakah kondisinya benar atau salah. Oleh karena itu contoh berikut akan gagal jika banneris null(perhatikan akses properti di baris kedua):

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

Anda harus berhati-hati saat menggunakannya. Saya sarankan membaca jawaban lain untuk pendekatan alternatif (lebih aman).

UPDATE 2: Melihat ke belakang, pendekatan ini tidak hanya berbahaya tetapi juga sangat sulit. Ini adalah contoh khas ketika seorang pengembang (saya) mencoba untuk mentransfer pola dan pendekatan yang dia tahu dari satu daerah ke daerah lain tetapi tidak benar-benar berfungsi (dalam hal ini bahasa templat lain).

Jika Anda memerlukan elemen kondisional, lakukan seperti ini:

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

Jika Anda juga membutuhkan cabang lain, cukup gunakan operator ternary:

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

Itu jauh lebih pendek, lebih elegan dan aman. Saya menggunakannya sepanjang waktu. Satu-satunya kelemahan adalah bahwa Anda tidak dapat melakukan else ifpercabangan semudah itu tetapi itu biasanya tidak umum.

Bagaimanapun, ini dimungkinkan berkat cara kerja operator logis dalam JavaScript. Operator logis bahkan memungkinkan trik kecil seperti ini:

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

1
Terima kasih. Saya sarankan membaca github.com/facebook/react/issues/690 Tautan ini telah diposting di komentar di bawah pertanyaan ini dan saya perhatikan setelah saya memposting solusi saya. Jika Anda memeriksanya, beberapa pria menyebutkan solusi ini juga tetapi tidak merekomendasikannya. Saya pribadi berpikir tidak apa-apa, setidaknya dalam kasus OP, tetapi memang benar bahwa cara ini tidak sempurna (tidak ada cara yang baik untuk mendefinisikan cabang lain misalnya). Bagaimanapun, itu layak dibaca.
tobik

1
Tidak yakin apakah ini masih berfungsi karena versi terbaru tampaknya memerlukan nilai yang dikembalikan menjadi aReactElement
srph

Hanya membungkusnya dengan elemen lain, <span>atau <div>.
tobik

Ada masalah ketika saya mencoba menggunakan ini untuk membuat <td> atau kosong di <table>, karena <noscript> tidak dapat diterima sebagai anak untuk <tr>. Kalau tidak, itu bekerja dengan baik untuk saya.
Green Su

1
Jika Anda akan melakukan ini, ada metode transpilasi yang cukup bagus: npmjs.com/package/jsx-control-statements
steve

82

Secara pribadi, saya benar-benar berpikir ekspresi terner menunjukkan ( JSX In Depth ) adalah cara paling alami yang sesuai dengan standar ReactJs.

Lihat contoh berikut. Ini agak berantakan pada pandangan pertama tetapi bekerja dengan cukup baik.

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

Catatan: kurung sama dengan pengembalian komponen, sehingga konten Anda perlu dikelilingi oleh <div> </div>.
JoeTidee

@ Chiedo mengapa Anda lebih suka jawaban populer? Ini sepertinya bekerja dengan baik.
Snowman

2
@oby Saya pikir jawaban populer lebih dinamis dan menghasilkan fungsi rendering yang lebih bersih. Dengan pendekatan ini, apa yang terjadi jika Anda memiliki beberapa persyaratan? Anda sekarang akan memiliki kegilaan bersarang dengan format aneh ini dan jika dua area terpisah membutuhkan perubahan yang sama berdasarkan pada kondisi, Anda sekarang harus menulis ulang kondisi tersebut lagi. Hanya pendapat saya saja! :)
Chiedo

halaman terkait juga cukup berguna: facebook.github.io/react/docs/…
Neil

46

Anda juga dapat menulis seperti itu

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

Jika Anda state.banneradalah nullatau undefined, sisi kanan kondisinya dilewati.


41

The Ifkomponen gaya ini berbahaya karena blok kode selalu dieksekusi terlepas dari kondisi tersebut. Sebagai contoh, ini akan menyebabkan nol perkecualian jika banneradalah 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>
  );
}

Opsi lain adalah menggunakan fungsi sebaris (terutama berguna dengan pernyataan lain):

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

Opsi lain dari masalah reaksi :

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
Dari semua solusi sejauh ini, fungsi inline tampaknya paling elegan dan lurus ke depan. Apa pun yang harus diperhatikan?
suryasankar

22

&& + gaya kode + komponen kecil

Sintaks tes sederhana + konvensi gaya kode + komponen kecil yang fokus bagi saya adalah opsi yang paling mudah dibaca di luar sana. Anda hanya perlu merawat nilai-nilai palsu seperti false, 0atau "".

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

lakukan notasi

ES7 stage-0 do notation syntax juga sangat bagus dan saya akan menggunakannya ketika IDE saya mendukungnya dengan benar:

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

Lebih detail di sini: ReactJs - Membuat komponen "Jika" ... ide yang bagus?


Info non-dasar gratis: yang pertama disebutshort-circuit syntax
sospedra

1
@Deerloper Saya kira perbedaan antara && dan & adalah salah satu hal pertama yang kita pelajari di sekolah komputer, tetapi beberapa orang mungkin tidak tahu sehingga bukan ide yang buruk untuk memberikan penjelasan lebih lanjut: en.wikipedia.org/wiki/Short-circuit_evaluation
Sebastien Lorber

Benar, tetapi mereka mengajarkannya sebagai bagian dari pernyataan kondisional klasik. Saya telah menemukan banyak orang bingung tentang menggunakan korsleting untuk membuat komponen Bereaksi;)
sospedra

22

Sederhana, buat fungsi.

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

Ini adalah pola yang saya ikuti secara pribadi sepanjang waktu. Membuat kode sangat bersih dan mudah dimengerti. Terlebih lagi itu memungkinkan Anda untuk refactor Bannerke komponennya sendiri jika terlalu besar (atau digunakan kembali di tempat lain).



11

Seperti yang telah disebutkan dalam jawaban, JSX memberi Anda dua opsi

  • Operator ternary

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

  • Kata hubung logis

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


Namun, itu tidak berhasil price == 0 .

JSX akan membuat cabang palsu dalam kasus pertama dan dalam kasus konjungsi logis, tidak ada yang akan diberikan. Jika properti mungkin 0, gunakan saja pernyataan di luar JSX Anda.


Itu bukan masalah BEJ. Itu kondisinya sendiri, bahkan di JS polos akan berperilaku sama. Jika Anda menginginkan nomor apa pun, cukup gunakan typeof(this.state.price) === "number"sebagai kondisinya (dalam kedua varian).
Kroltan

8

Komponen ini berfungsi ketika Anda memiliki lebih dari satu elemen di dalam cabang "jika":

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

Pemakaian:

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 seseorang berpikir bahwa komponen ini tidak baik untuk membaca kode. Tetapi dalam pikiran saya, Html dengan javascript lebih buruk


Seperti jawaban If di sini, ini masih akan mengeksekusi kondisi salah meskipun tidak ditampilkan.
Keegan 82

3

Sebagian besar contoh adalah dengan satu baris "html" yang diterjemahkan secara kondisional. Ini sepertinya terbaca bagi saya ketika saya memiliki beberapa baris yang perlu diterjemahkan secara kondisional.

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

Contoh pertama adalah baik karena alih-alih nullkita dapat membuat beberapa konten lain seperti{this.props.showContent ? content : otherContent}

Tetapi jika Anda hanya perlu menampilkan / menyembunyikan konten ini bahkan lebih baik karena Boolean, Null, dan Undefined Diabaikan

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

Ada solusi lain, jika komponen untuk Bereaksi :

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

Saya menggunakan pintasan yang lebih eksplisit: Ekspresi Fungsi yang Segera Dibawa (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

Ada juga versi satu baris yang sangat bersih ... {this.props.product.title || "Tanpa judul" }

Yaitu:

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

Apakah itu berhasil dengan sampel saya di atas? Di mana spanduk div seharusnya tidak muncul jika tidak ada spanduk prop?
Jack Allan

1

Saya membuat https://github.com/ajwhite/render-if baru-baru ini untuk membuat elemen secara aman hanya jika predikat lolos .

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

atau

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

//...

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

1

Anda dapat memasukkan elemen secara kondisional menggunakan operator ternary seperti:

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

Anda dapat menggunakan fungsi dan mengembalikan komponen dan menjaga tipis fungsi 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

Inilah pendekatan saya menggunakan 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/

Saya menggunakan kode seperti:

{opened && <SomeElement />}

Itu akan membuat SomeElementhanya jika openeditu benar. Ini bekerja karena cara JavaScript menyelesaikan kondisi logis:

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

Seperti yang Reactakan diabaikan false, saya menemukan cara yang sangat baik untuk membuat beberapa elemen bersyarat.


1

Mungkin ini membantu seseorang yang menemukan pertanyaan: Semua rendering Bersyarat dalam Bereaksi Ini adalah artikel tentang semua opsi berbeda untuk rendering bersyarat dalam Bereaksi.

Pengambilan kunci kapan harus menggunakan rendering bersyarat mana:

** jika lain

  • adalah rendering bersyarat paling dasar
  • ramah pemula
  • gunakan jika untuk keluar awal dari metode render dengan mengembalikan nol

** operator ternary

  • gunakan untuk pernyataan if-else
  • itu lebih ringkas daripada jika-lain

** logis operator &&

  • gunakan ketika satu sisi operasi ternary akan mengembalikan nol

** beralih kasus

  • bertele-tele
  • hanya bisa digarisbawahi dengan fungsi self invaging
  • hindari itu, gunakan enum sebagai gantinya

** enum

  • sempurna untuk memetakan berbagai negara
  • sempurna untuk memetakan lebih dari satu syarat

** rendering bersyarat multi-level / bersarang

  • hindarilah demi keterbacaan
  • pisahkan komponen menjadi komponen yang lebih ringan dengan rendering kondisional mereka sendiri
  • gunakan HOCs

** HOC

  • menggunakannya untuk melindungi rendering bersyarat
  • komponen dapat fokus pada tujuan utama mereka

** komponen templating eksternal

  • Hindari mereka dan merasa nyaman dengan JSX dan JavaScript

1

Dengan ES6, Anda dapat melakukannya dengan one-liner sederhana

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

"show" adalah boolean dan Anda menggunakan kelas ini oleh

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

1
Buruk. Itu akan selalu dihitung.
Qwertiy

0

Saya tidak berpikir ini telah disebutkan. Ini seperti jawaban Anda sendiri tetapi saya pikir ini lebih sederhana. Anda selalu dapat mengembalikan string dari ekspresi dan Anda bisa membuat jsx di dalam ekspresi, jadi ini memungkinkan untuk ekspresi inline yang mudah dibaca.

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

Saya suka dengan explicitness dari Function Function-Unlimited Function Expressions ( IIFE) dan if-elseberulang render callbacks-ulang 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>
  );
}

Anda hanya perlu membiasakan diri dengan IIFEsintaks, {expression}adalah sintaks React yang biasa, di dalamnya hanya mempertimbangkan bahwa Anda sedang menulis sebuah fungsi yang memanggil dirinya sendiri.

function() {

}()

yang perlu dibungkus dalam parens

(function() {

}())

0

Ada juga teknik menggunakan render props untuk mengkondisikan render komponen. Manfaatnya adalah bahwa render tidak akan mengevaluasi sampai kondisi terpenuhi, sehingga tidak ada kekhawatiran untuk nilai nol dan tidak ditentukan .

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

Ketika harus hanya membuat sesuatu jika kondisi yang berlalu terpenuhi, Anda dapat menggunakan sintaks:

{ condition && what_to_render }

Kode dengan cara ini akan terlihat seperti ini:

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

Ada, tentu saja, cara lain yang sah untuk melakukan ini, semua terserah preferensi dan kesempatan. Anda dapat mempelajari lebih banyak cara tentang cara melakukan rendering bersyarat dalam Bereaksi dalam artikel ini jika Anda tertarik!


-1

Hanya untuk menambahkan opsi lain - jika Anda suka / mentolerir skrip kopi, Anda dapat menggunakan kopi-reaksi untuk menulis BEJ Anda dalam hal ini, jika pernyataan selain dapat digunakan karena merupakan ekspresi dalam skrip kopi dan bukan pernyataan:

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.