Mengoper Props ke Komponen

Komponen React menggunakan props untuk berkomunikasi antara satu dengan yang lainnya. Setiap komponen induk bisa mengirim beberapa informasi pada komponen-komponen anaknya dengan memberikan mereka props. Props mungkin akan mengingatkan Anda dengan atribut HTML, namun Anda bisa mengirim nilai JavaScript apapun melalui itu, termasuk objek, senarai, bahkan fungsi.

You will learn

  • Bagaimana cara mengoper props ke komponen
  • Bagaimana cara membaca props dari komponen
  • Bagaimana cara memberi nilai bawaan untuk props
  • Bagaimana cara mengirim beberapa JSX ke dalam component
  • Bagaimana props berubah seiring waktu

Props umum

Props adalah informasi yang Anda kirimkan pada tag JSX. Sebagai contoh, className, src, alt, width, dan height adalah beberapa contoh dari props yang bisa Anda kirimkan pada <img>:

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  );
}

export default function Profile() {
  return (
    <Avatar />
  );
}

Props yang bisa dikirimkan pada tag <img> sudah didefinisikan sebelumnya (ReactDOM menyesuaikan dengan standar HTML). Namun Anda bisa mengirimkan props apapun pada komponen Anda sendiri, Misalnya <Avatar>, untuk dikustomisasi. Begini caranya!

Mengoper props ke komponen

Pada kode ini, komponen Profile tidak mengirimkan props apapun pada komponen anaknya, yaitu Avatar:

export default function Profile() {
return (
<Avatar />
);
}

Anda bisa memberi Avatar beberapa props dalam dua langkah.

Langkah 1: Mengoper props ke komponen anak

Pertama-tama, kirimkan beberapa props pada Avatar. Sebagai contoh, mari kirimkan dua props: person (sebuah objek), dan size (sebuah angka):

export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}

Note

Jika dobel kurung kurawal setelah person= membuat Anda bingung, ingatlah bahwa mereka hanyalah sebuah objek dalam kurung kurawal JSX.

Sekarang Anda bisa membaca props tersebut di dalam komponen Avatar.

Langkah 2: Membaca props di dalam komponen anak

Anda bisa membaca props tersebut dengan mendaftarkan namanya yaitu person, size dengan cara dipisahkan dengan koma di dalam ({ dan }) langsung setelah function Avatar. Hal ini memungkinkan Anda untuk menggunakannya di dalam kode Avatar, sama halnya saat Anda menggunakan variabel.

function Avatar({ person, size }) {
// sekarang person dan size bisa Anda pakai di sini
}

Tambahkan beberapa logika pada Avatar yang menggunakan props person dan size untuk di-render, dan selesai.

Sekarang Anda bisa membuat Avatar untuk di-render dalam banyak cara dan dengan props yang berbeda. Cobalah utak-atik nilainya!

import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi', 
          imageId: 'YfeOqp2'
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'Aklilu Lemma', 
          imageId: 'OKS67lh'
        }}
      />
      <Avatar
        size={50}
        person={{ 
          name: 'Lin Lanying',
          imageId: '1bX5QH6'
        }}
      />
    </div>
  );
}

Props membuat Anda berpikir tentang komponen induk dan komponen anak secara terpisah. Sebagai contoh, Anda bisa mengubah props person atau size di dalam Profile tanpa perlu memikirkan bagaimana Avatar menggunakannya. Begitupun, Anda bisa mengubah bagaimana Avatar menggunakan props tersebut, tanpa menghiraukan Profile.

Anda bisa menganggap props seperti “kenop” yang bisa disesuaikan. Props berperan sama seperti arguments pada functions—Nyatanya, props adalah satu-satunya argument pada komponen Anda! Komponen fungsi React menerima satu argument, sebuah objek props.:

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

Biasanya Anda tidak memerlukan objek props secara utuh, maka Anda memecahnya menjadi props tersendiri.

Pitfall

Jangan melewatkan pasangan kurung kurawal { dan } di dalam ( dan ) saat menyatakan props:

function Avatar({ person, size }) {
// ...
}

Sintaksis ini disebut “destructuring” dan ini berfungsi untuk membaca properti dari parameter fungsi:

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

Menentukan nilai bawaaan untuk prop

Jika Anda ingin memberi prop nilai bawaan untuk berjaga-jaga saat tidak ada nilai yang ditentukan, Anda bisa melakukannya dengan destructring lalu menaruh = dan nilai bawaannya tepat setelah parameter:

function Avatar({ person, size = 100 }) {
// ...
}

Sekarang, jika <Avatar person={...} /> di-render tanpa menerima prop size, size akan bernilai 100.

Nilai bawaan hanya akan terpakai jika prop size tidak ada atau jika Anda mengirim size={undefined}. Namun jika Anda mengirim size={null} atau size={0}, nilai bawaan tidak akan terpakai.

Meneruskan props dengan sintaksis spread JSX

Terkadang, mengirim props bisa sangat repetitif:

function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}

Tidak ada salahnya dengan kode yang repetitif—itu membuatnya lebih mudah untuk dibaca. Namun terkadang Anda mungkin lebih menyukai keringkasan. Beberapa komponen meneruskan semua propsnya kepada komponen anaknya, persis seperti yang Profile lakukan dengan Avatar. Karena mereka tidak menggunakan propsnya secara langsung, ini akan masuk akal untuk menggunakan sintaksis ”spread” yang mana lebih ringkas:

function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}

Ini akan meneruskan semua props milik Profile pada Avatar tanpa menuliskannya satu-persatu.

Gunakan sintaksis spread dengan batasan. Jika Anda menggunakannya pada setiap komponen, maka ada yang salah. Seringkali, ini menunjukan bahwa Anda perlu memecah komponen Anda dan mengirim anaknya sebagai JSX. Mari kita bahas!

Mengoper JSX sebagai anak

Sudah umum untuk menyisipkan tag bawaan pada peramban:

<div>
<img />
</div>

Terkadang Anda ingin menyisipkan komponen Anda dengan cara yang sama:

<Card>
<Avatar />
</Card>

Saat Anda menyisipkan konten ke dalam tag JSX, komponen induk akan menerima konten tersebut dalam bentuk prop yang disebut children. Sebagai contoh, Komponen Card di bawah akan menerima prop children yang diisi <Avatar /> lalu me-rendernya dengan cara membungkusnya ke dalam div:

import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

Cobalah ubah <Avatar> yang ada di dalam <Card> dengan teks untuk melihat bagaimana komponen Card bisa disisipkan konten apapun. Komponen tersebut tidak perlu “mengetahui” apa yang di-render di dalamnya. Anda lihat betapa fleksibelnya hal ini.

Anda bisa menganggap bahwa komponen dengan prop children itu mempunyai “lubang” yang bisa “diisi” oleh komponen induknya dengan JSX secara bebas. Anda akan sering menggunakan prop children sebagai pembungkus: panels, grids, dan lainnya.

A puzzle-like Card tile with a slot for "children" pieces like text and Avatar

Illustrated by Rachel Lee Nabors

Bagaimana props berubah seiring waktu

Komponen Clock di bawah menerima dua props dari komponen induknya: color dan time. (Kode untuk komponen induknya dihilangkan karena itu menggunakan state, yang mana belum kita bahas untuk saat ini.)

Coba ubahlah warna pada kotak pilihan di bawah:

export default function Clock({ color, time }) {
  return (
    <h1 style={{ color: color }}>
      {time}
    </h1>
  );
}

Contoh ini menggambarkan bahwa sebuah komponen mungkin menerima props yang berbeda seiring waktu. Props tidak selalu bersifat tetap! Begini, prop time berubah setiap detik, dan prop color berubah ketika Anda memilih warna lain. Data pada komponen akan ditampilkan props kapan saja, bukan hanya di awal.

Bagaimanapun, props bersifat immutable—Sebuah istilah pada ilmu komputer yang berarti “tidak dapat diubah”. Saat sebuah komponen ingin mengubah propsnya (sebagai contoh, untuk merespon interaksi pengguna atau merespon data baru), mereka harus “meminta” komponen induknya untuk mengirim dirinya props yang lain—objek baru! Lalu props yang lama akan disingkirkan, dan nantinya mesin JavasCript akan mengambil kembali memori yang dipakai oleh mereka.

Jangan mencoba untuk “mengubah props“. Ketika Anda perlu merespon masukan pengguna (misalnya mengubah warna yang dipilih), Anda akan memerlukan ”set state”, yang mana akan Anda pelajari pada State: Memori Milik Komponen.

Recap

  • Untuk mengoper props, tambahkan langsung ke JSX, seperti yang Anda lakukan dengan atribut HTML.
  • Untuk membaca props, gunakan function Avatar({ person, size }) sintaksis destructuring.
  • Anda bisa memberi nilai bawaan seperti size = 100, yang mana akan digunakan untuk props yang kosong dan undefined.
  • Anda bisa meneruskan semua props dengan <Avatar {...props} /> sintaksis spread JSX, Namun jangan terlalu sering menggunakannya!
  • Menyisipkan JSX seperti <Card><Avatar /></Card> akan menghasilkan prop children milik komponen Card.
  • Props hanya untuk dibaca pada satu waktu: setiap render menghasilkan props yang baru.
  • Anda tidak bisa mengubah props. Saat Anda butuh interaktivitas, Anda akan membutuhkan state.

Challenge 1 of 3:
Mengekstrak komponen

Komponen Gallery ini berisi dua markup yang sama persis. Ekstraklah menjadi komponen Profile untuk mengurangi duplikasi. Anda perlu memilih props apa saja yang akan dikirimkan.

import { getImageUrl } from './utils.js';

export default function Gallery() {
  return (
    <div>
      <h1>Notable Scientists</h1>
      <section className="profile">
        <h2>Maria Skłodowska-Curie</h2>
        <img
          className="avatar"
          src={getImageUrl('szV5sdG')}
          alt="Maria Skłodowska-Curie"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profesi: </b> 
            Fisikawan dan kimiawan
          </li>
          <li>
            <b>Penghargaan: 4 </b> 
            (Penghargaan Nobel Fisika, Penghargaan Nobel Kimia, Medali Davy, Medali Matteucci)
          </li>
          <li>
            <b>Telah Menemukan: </b>
            polonium (unsur kimia)
          </li>
        </ul>
      </section>
      <section className="profile">
        <h2>Katsuko Saruhashi</h2>
        <img
          className="avatar"
          src={getImageUrl('YfeOqp2')}
          alt="Katsuko Saruhashi"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profesi: </b> 
            Ahli Geokimia
          </li>
          <li>
            <b>Penghargaan: 2 </b> 
            (Penghargaan Miyake Geokimia, Penghargaan Tanaka)
          </li>
          <li>
            <b>Telah Menemukan: </b>
            sebuah metode untuk mengukur karbon dioksida pada air laut
          </li>
        </ul>
      </section>
    </div>
  );
}