Conditional Rendering

Komponen anda sering diperlukan untuk menampilkan hal yang berbeda tergantung dari beberapa kondisi yang berbeda. Di React, anda dapat melakukan render JSX secara bersyarat menggunakan sintaks JavaScript seperti pernyataan if, &&, dan ? : operator.

You will learn

  • Cara mengembalikan JSX yang berbeda tergantung dari suatu kondisi
  • Bagaimana cara memasukkan atau mengecualikan sepotong JSX secara bersyarat
  • Pintasan sintaks bersyarat umum yang akan anda temukan di basis kode React

Mengembalikan JSX secara Bersyarat

Katakanlah anda memiliki komponen PackingList yang melakukan render pada beberapa Items, yang dapat ditandai secara dikemas atau tidak:

function Item({ name, isPacked }) {
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Andrian Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Perhatikan bahwa beberapa komponen Item memiliki properti isPacked yang disetel menjadi true daripada false. Anda ingin menambahkan tanda centang (✔) ke Item yang dikemas jika isPacked={true}.

Anda dapat menulis ini sebagai pernyataan if/else seperti ini:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

Jika properti isPacked adalah true, kode ini mengembalikan JSX tree yang berbeda. Dengan perubahan ini, beberapa item mendapat tanda centang di bagian akhir:

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Andrian Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Coba melakukan edit apa yang dikembalikan dalam kedua kasus tersebut, dan lihat bagaimana hasilnya berubah!

Perhatikan bagaimana anda membuat logika bercabang dengan pernyataan if dan return menggunakan JavaScript. Di React, alur kontrol (seperti kondisi) ditangani oleh JavaScript.

Tidak mengembalikan apa pun secara bersyarat dengan null

Dalam kondisi tertentu, anda tidak ingin me-render apa pun. Sebagai Contoh, katakan anda tidak mau menampilkan item yang dikemas. Sebuah komponen harus mengembalikan sesuatu. Dalam kasus ini, anda dapat mengambalikan null:

if (isPacked) {
return null;
}
return <li className="item">{name}</li>;

Jika isPacked adalah true, komponen tidak akan mengembalikan apa pun, null. Jika tidak, itu akan mengembalikan JSX untuk di-render.

function Item({ name, isPacked }) {
  if (isPacked) {
    return null;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Andrian Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Dalam praktiknya, mengembalikan null dari sebuah komponen itu tidak umum karena dapat mengejutkan developer yang mencoba untuk me-render-nya. Lebih sering, anda akan menyertakan atau mengecualikan komponen secara bersyarat di komponen induk JSX. Berikut adalah cara untuk melakukannya!

Secara Bersyarat memasukkan JSX

Pada contoh sebelumnya, anda mengontrol JSX tree mana (if any!) yang akan dikembalikan oleh komponen. Anda mungkin telah memperhatikan beberapa duplikasi dalam hasil render:

<li className="item">{name}</li>

mirip dengan

<li className="item">{name}</li>

Kedua branches bersyarat tersebut mengembalikan <li className="item">...</li>:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

Meskipun duplikasi ini tidak berbahaya, ini dapat membuka kode anda lebih susah untuk di-maintain. Bagaimana jika anda ingi mengganti classNamenya? Anda harus melakukannya di dua tempat dalam kode anda! Dalam situasi seperti itu, anda dapat menyertakan sedikit JSX secara bersyarat untuk membuat kode anda lebih DRY.

Operator (? :) bersyarat (ternary)

JavaScript memiliki syntax yang ringkas untuk menulis ekspresi bersyarat — operator bersyarat atau sering disebut sebagai “ternary operator”.

Daripada ini:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

Anda dapat menulis ini:

return (
<li className="item">
{isPacked ? name + ' ✔' : name}
</li>
);

anda dapat membacanya sebagai “jika isPacked adalah true, maka (?) render name + ' ✔', jika tidak (:) render name.

Deep Dive

Apakah kedua contoh tersebut sepenuhnya sama?

Jika anda berasal dari latar belakang pemrograman berorientasi objek, anda mungkin berasumsi bahwa kedua contoh tersebut sedikit berbeda karena salah satunya dapat membuat dua jenis “instansi” <li> berbeda. Tetapi elemen JSX bukan “instansi” karena mereka tidak memiliki state internal dan bukan node DOM yang sebenarnya. Itu deskripsi ringan, seperti cetak biru. Jadi kedua contoh ini, sebenarnya, adalah benar-benar sama. Preserving and Resetting State menjelaskan lebih detil bagaimana hal ini bekerja.

Sekarang katakanlah anda ingin membungkus teks item yang sudah selesai ke dalam tag HTML lain, seperti <del> untuk mencoretnya. Anda bahkan dapat menambahkan lebih banyak baris baru dan tanda kurung sehingga lebih mudah untuk menyarankan lebih banyak JSX di setiap kasus:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {isPacked ? (
        <del>
          {name + ' ✔'}
        </del>
      ) : (
        name
      )}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Andrian Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Gaya ini bekerja dengan baik untuk kondisi yang sederhana, tetapi gunakan dengan secukupnya. Jika komponen anda berantakan dengan terlalu banyak markup bersyarat bersarang (nested conditional markup), pertimbangkan untuk mengekstrak komponen turunan untuk membersihkan semuanya. Di React, markup adalah bagian dari kode anda, sehingga anda dapat menggunakan alat seperti variabel (variables) dan fungsi (functions) untuk merapikan ekspresi yang kompleks.

Operator Logis AND (&&)

Pintasan umum lainnya yang akan anda temui adalah JavaScript logical AND (&&) operator. Di Dalam komponen React, hal tersebut sering muncul ketika anda ingin me-render beberapa JSX apabila memiliki kondisi true, atau tidak me-render sebaliknya. Dengan &&, anda dapat me-render tanda centang secara bersyarat hanya jika isPacked adalah true:

return (
<li className="item">
{name} {isPacked && '✔'}
</li>
);

Anda dapat membaca ini sebagai “jika isPacked, maka (&&) render tanda centang, jika tidak, tidak render apa pun”.

Seperti berikut:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Andrian Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Ekspresi && JavaScript mengembalikan nilai sisi kanannya (dalam kasus ini, tanda centang) jika sisi kirinya (kondisi kita) adalah true. Tetapi jika kondisinya adalah false, seluruh ekspresi menjadi false. React menganggap false sebagai sebuah “lubang” pada JSX tree, sama seperti null atau undefined, dan tidak me-render apa pun di tempatnya.

Pitfall

Jangan menaruh angka di sisi kiri &&.

Untuk menguji kondisi tersebut, JavaScript mengubah sisi kiri menjadi sebuah *boolean* secara otomatis. Namun, jika sisi kiri adalah 0, maka seluruh ekspresi akan mendapatkan nilai (0) tesebut, dan React akan dengan senang hati me-render 0 daripada tidak sama sekali.

Sebagai contoh, kesalahan umum yang sering terjadi adalah menulis kode seperti messageCount && <p>Pesan Baru</p>. Sangat mudah untuk berasumsi bahwa itu tidak me-render/menghasilkan apa-apa ketika messageCount adalah 0, tapi itu benar-benar me-render 0 itu sendiri!

Untuk memperbaikinya, jadikan sisi kiri sebagai *boolean*: messageCount > 0 && <p>Pesan Baru</p>.

Conditionally assigning JSX to a variable

When the shortcuts get in the way of writing plain code, try using an if statement and a variable. You can reassign variables defined with let, so start by providing the default content you want to display, the name:

let itemContent = name;

Use an if statement to reassign a JSX expression to itemContent if isPacked is true:

if (isPacked) {
itemContent = name + " ✔";
}

Curly braces open the “window into JavaScript”. Embed the variable with curly braces in the returned JSX tree, nesting the previously calculated expression inside of JSX:

<li className="item">
{itemContent}
</li>

This style is the most verbose, but it’s also the most flexible. Here it is in action:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✔";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Like before, this works not only for text, but for arbitrary JSX too:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = (
      <del>
        {name + " ✔"}
      </del>
    );
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

If you’re not familiar with JavaScript, this variety of styles might seem overwhelming at first. However, learning them will help you read and write any JavaScript code — and not just React components! Pick the one you prefer for a start, and then consult this reference again if you forget how the other ones work.

Recap

  • In React, you control branching logic with JavaScript.
  • You can return a JSX expression conditionally with an if statement.
  • You can conditionally save some JSX to a variable and then include it inside other JSX by using the curly braces.
  • In JSX, {cond ? <A /> : <B />} means “if cond, render <A />, otherwise <B />.
  • In JSX, {cond && <A />} means “if cond, render <A />, otherwise nothing”.
  • The shortcuts are common, but you don’t have to use them if you prefer plain if.

Challenge 1 of 3:
Show an icon for incomplete items with ? :

Use the conditional operator (cond ? a : b) to render a ❌ if isPacked isn’t true.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}