Sandungan

Menggunakan Children tidaklah umum dan dapat menyebabkan kode yang mudah rusak. Lihat alternatif umum.

Children memungkinkan Anda memanipulasi dan mengubah JSX yang Anda terima sebagai prop children.

const mappedChildren = Children.map(children, child =>
<div className="Row">
{child}
</div>
);

Referensi

Children.count(children)

Panggil Children.count(children) untuk menghitung jumlah anak dalam struktur data children.

import { Children } from 'react';

function RowList({ children }) {
return (
<>
<h1>Jumlah baris: {Children.count(children)}</h1>
...
</>
);
}

Lihat contoh lainnya di bawah ini.

Parameter

  • children: Nilai dari prop children yang diterima oleh komponen Anda.

Kembalian

Jumlah simpul dalam children ini.

Catatan Penting

  • Simpul kosong (null, undefined, dan Boolean), string, angka, dan elemen React dihitung sebagai simpul individu. Larik tidak dihitung sebagai simpul individu, tetapi anak-anaknya dihitung sebagai simpul individu. Penjelajahan tidak masuk lebih dalam dari elemen React: mereka tidak di-render, dan anak-anaknya tidak dijelajahi. Fragmen tidak dijelajahi.

Children.forEach(children, fn, thisArg?)

Panggil Children.forEach(children, fn, thisArg?) untuk menjalankan beberapa kode untuk setiap anak dalam struktur data children.

import { Children } from 'react';

function SeparatorList({ children }) {
const result = [];
Children.forEach(children, (child, index) => {
result.push(child);
result.push(<hr key={index} />);
});
// ...

Lihat contoh lainnya di bawah ini.

Parameter

  • children: Nilai dari prop children yang diterima oleh komponen Anda.
  • fn: Fungsi yang ingin Anda jalankan untuk setiap anak, serupa dengan metode callback dari larik forEach. Fungsi ini akan dipanggil dengan anak sebagai argumen pertama dan indeksnya sebagai argumen kedua. Indeks dimulai dari 0 dan bertambah pada setiap pemanggilan.
  • opsional thisArg: Nilai this yang digunakan untuk memanggil fungsi fn. Jika diabaikan, maka akan menjadi undefined.

Kembalian

Children.forEach mengembalikan undefined.

Catatan Penting

  • Simpul kosong (null, undefined, dan Boolean), string, angka, dan elemen React dihitung sebagai simpul individual. Larik tidak dihitung sebagai simpul individu, tetapi anak-anaknya dihitung sebagai simpul individu. Penjelajahan tidak masuk lebih dalam dari elemen React: mereka tidak di-render, dan anak-anaknya tidak dijelajahi. Fragmen tidak dijelajahi.

Children.map(children, fn, thisArg?)

Panggil Children.map(children, fn, thisArg?) untuk memetakan atau mentransformasi setiap anak dalam struktur data children.

import { Children } from 'react';

function RowList({ children }) {
return (
<div className="RowList">
{Children.map(children, child =>
<div className="Row">
{child}
</div>
)}
</div>
);
}

Lihat contoh lainnya di bawah ini.

Parameter

  • children: Nilai dari prop children yang diterima oleh komponen Anda.
  • fn: Fungsi pemetaan, mirip dengan metode callback dari larik map. Fungsi ini akan dipanggil dengan anak sebagai argumen pertama dan indeksnya sebagai argumen kedua. Indeks dimulai dari 0 dan bertambah pada setiap pemanggilan. Anda harus mengembalikan sebuah simpul React dari fungsi ini. Node ini dapat berupa node kosong (null, undefined, atau Boolean), string, angka, elemen React, atau larik simpul React lainnya.
  • opsional thisArg: Nilai this yang digunakan untuk memanggil fungsi fn. Jika diabaikan, maka akan menjadi undefined.

Kembalian

Jika children adalah null atau undefined, akan mengembalikan nilai yang sama.

Jika tidak, kembalikan larik flat yang terdiri dari simpul yang Anda kembalikan dari fungsi fn. Larik yang dikembalikan akan berisi semua simpul yang Anda kembalikan kecuali null dan undefined.

Catatan Penting

  • Simpul kosong (null, undefined, dan Boolean), string, angka, dan elemen React dihitung sebagai simpul individual. Larik tidak dihitung sebagai simpul individu, tetapi anak-anaknya dihitung sebagai simpul individu. Penjelajahan tidak masuk lebih dalam dari elemen React: mereka tidak di-render, dan anak-anaknya tidak dijelajahi. Fragmen tidak dijelajahi.

  • Jika Anda mengembalikan sebuah elemen atau larik elemen dengan kunci dari fn, kunci elemen yang dikembalikan akan secara otomatis digabungkan dengan kunci item asli yang sesuai dari children. Jika Anda mengembalikan beberapa elemen dari fn dalam sebuah larik, kuncinya hanya perlu unik secara lokal satu sama lain.


Children.only(children)

Panggil Children.only(children) untuk menyatakan bahwa children merepresentasikan satu elemen React.

function Box({ children }) {
const element = Children.only(children);
// ...

Parameter

  • children: Nilai dari prop children yang diterima oleh komponen Anda.

Kembalian

Jika children adalah elemen yang valid, kembalikan elemen tersebut.

Jika tidak, akan lemparkan sebuah error.

Catatan Penting

  • Metode ini selalu melempar jika Anda mengoper sebuah array (seperti nilai kembalian dari Children.map) sebagai children. Dengan kata lain, metode ini memaksakan bahwa children adalah sebuah elemen React, bukan sebuah array dengan satu elemen.

Children.toArray(children)

Panggil Children.toArray(children) untuk membuat larik dari struktur data children.

import { Children } from 'react';

export default function ReversedList({ children }) {
const result = Children.toArray(children);
result.reverse();
// ...

Parameter

  • children: Nilai dari prop children yang diterima oleh komponen Anda.

Kembalian

Mengembalikan larik yang flat dari elemen dalam children.

Catatan Penting

  • Simpul kosong (null, undefined, dan Boolean) akan dihilangkan dalam larik yang dikembalikan. Kunci elemen yang dikembalikan akan dihitung dari kunci elemen asli dan tingkat persarangan serta posisinya. Hal ini memastikan bahwa pe-flatten-an larik tidak mengakibatkan perubahan perilaku.

Penggunaan

Mentransformasikan anak-anak

Untuk mentransformasi anak-anak JSX yang diterima komponen Anda sebagai prop children, panggil Children.map:

import { Children } from 'react';

function RowList({ children }) {
return (
<div className="RowList">
{Children.map(children, child =>
<div className="Row">
{child}
</div>
)}
</div>
);
}

Pada contoh di atas, RowList membungkus setiap anak yang diterimanya ke dalam wadah <div className="Row">. Sebagai contoh, anggaplah komponen induk meneruskan tiga tag <p> sebagai props children ke RowList:

<RowList>
<p>Ini adalah item pertama.</p>
<p>Ini adalah item kedua</p>
<p>Ini adalah item ketiga.</p>
</RowList>

Kemudian, dengan implementasi RowList di atas, hasil akhir yang di-render akan terlihat seperti ini:

<div className="RowList">
<div className="Row">
<p>Ini adalah item pertama.</p>
</div>
<div className="Row">
<p>Ini adalah item kedua</p>
</div>
<div className="Row">
<p>Ini adalah item ketiga.</p>
</div>
</div>

Children.map mirip dengan mentransformasi array dengan map(). Perbedaannya adalah bahwa struktur data children dianggap sebagai buram. Artinya, meskipun terkadang children berupa array, Anda tidak boleh mengasumsikannya sebagai array atau tipe data tertentu lainnya. Inilah sebabnya mengapa Anda harus menggunakan Children.map jika Anda perlu melakukan transformasi.

import { Children } from 'react';

export default function RowList({ children }) {
  return (
    <div className="RowList">
      {Children.map(children, child =>
        <div className="Row">
          {child}
        </div>
      )}
    </div>
  );
}

Pendalaman

Mengapa prop children tidak selalu berupa larik?

Dalam React, prop children dianggap sebagai struktur data buram. Artinya, Anda tidak boleh bergantung pada cara penytrukturannya. Untuk mengubah, memfilter, atau menghitung anak, Anda harus menggunakan metode-metode Children.

Pada praktiknya, struktur data children sering kali direpresentasikan sebagai sebuah larik secara internal. Namun, jika hanya ada satu child, maka React tidak akan membuat larik tambahan karena hal ini akan menyebabkan overhead memori yang tidak diperlukan. Selama Anda menggunakan metode Children dan tidak secara langsung mengintrospeksi prop children, kode Anda tidak akan rusak meskipun React mengganti bagaimana struktur datanya diimplementasikan.

Bahkan saat children berupa sebuah larik, Children.map memiliki perilaku khusus yang membantu. Sebagai contoh, Children.map menggabungkan beberapa key pada elemen yang dikembalikan dengan kunci pada children yang telah Anda berikan padanya. Hal ini memastikan anak JSX asli tidak “kehilangan” kunci meskipun dibungkus seperti pada contoh di atas.

Sandungan

Struktur data children tidak termasuk output yang di-render dari komponen yang Anda berikan sebagai JSX. Pada contoh di bawah ini, children yang diterima oleh RowList hanya berisi dua item, bukan tiga:

  1. <p>Ini adalah item pertama.</p>
  2. <MoreRows />

Inilah alasan mengapa hanya dua pembungkus baris yang dihasilkan dalam contoh ini:

import RowList from './RowList.js';

export default function App() {
  return (
    <RowList>
      <p>Ini adalah item pertama.</p>
      <MoreRows />
    </RowList>
  );
}

function MoreRows() {
  return (
    <>
      <p>Ini adalah item kedua</p>
      <p>Ini adalah item ketiga.</p>
    </>
  );
}

Tidak ada cara untuk mendapatkan keluaran yang di-render dari komponen dalam, seperti <MoreRows /> saat memanipulasi children. Inilah mengapa biasanya lebih baik menggunakan salah satu solusi alternatif.


Menjalankan beberapa kode untuk setiap anak

Panggil Children.forEach untuk mengulang setiap anak dalam struktur data children. Metode ini tidak mengembalikan nilai apa pun dan mirip dengan metode larik forEach. Anda dapat menggunakannya untuk menjalankan logika khusus seperti membuat larik Anda sendiri.

import { Children } from 'react';

export default function SeparatorList({ children }) {
  const result = [];
  Children.forEach(children, (child, index) => {
    result.push(child);
    result.push(<hr key={index} />);
  });
  result.pop(); // Hapus *separator* terakhir
  return result;
}

Sandungan

Seperti yang telah disebutkan sebelumnya, tidak ada cara untuk mendapatkan hasil render dari komponen dalam ketika memanipulasi children. Inilah sebabnya mengapa biasanya lebih baik menggunakan salah satu solusi alternatif.


Menghitung anak-anak

Panggil Children.count(children) untuk menghitung jumlah anak.

import { Children } from 'react';

export default function RowList({ children }) {
  return (
    <div className="RowList">
      <h1 className="RowListHeader">
        Jumlah baris: {Children.count(children)}
      </h1>
      {Children.map(children, child =>
        <div className="Row">
          {child}
        </div>
      )}
    </div>
  );
}

Sandungan

Seperti yang telah disebutkan sebelumnya, tidak ada cara untuk mendapatkan hasil render dari komponen dalam ketika memanipulasi children. Inilah sebabnya mengapa biasanya lebih baik menggunakan salah satu solusi alternatif.


Mengonversi anak menjadi larik

Panggil Children.toArray(children) untuk mengubah struktur data children menjadi larik JavaScript biasa. Hal ini memungkinkan Anda memanipulasi larik dengan metode larik bawaan seperti filter, sort, atau reverse.

import { Children } from 'react';

export default function ReversedList({ children }) {
  const result = Children.toArray(children);
  result.reverse();
  return result;
}

Sandungan

Seperti yang telah disebutkan sebelumnya, tidak ada cara untuk mendapatkan hasil render dari komponen dalam ketika memanipulasi children. Inilah sebabnya mengapa biasanya lebih baik menggunakan salah satu solusi alternatif.


Alternatif

Catatan

Bagian ini menjelaskan alternatif untuk API Children (dengan huruf kapital C) yang diimpor seperti berikut ini:

import { Children } from 'react';

Jangan tertukar dengan penggunaan prop children (huruf kecil c), yang merupakan hal yang baik dan dianjurkan.

Mengekspos beberapa komponen

Memanipulasi anak dengan metode Children sering kali menghasilkan kode yang mudah rusak. Ketika Anda mengoper children ke sebuah komponen di JSX, biasanya Anda tidak mengharapkan komponen tersebut untuk memanipulasi atau mengubah masing-masing children.

Jika memungkinkan, hindari penggunaan metode Children. Misalnya, jika Anda ingin setiap anak dari RowList dibungkus dengan <div className="Row">, ekspor komponen Row, dan secara manual membungkus setiap baris ke dalamnya seperti ini:

import { RowList, Row } from './RowList.js';

export default function App() {
  return (
    <RowList>
      <Row>
        <p>Ini adalah item pertama.</p>
      </Row>
      <Row>
        <p>Ini adalah item kedua</p>
      </Row>
      <Row>
        <p>Ini adalah item ketiga.</p>
      </Row>
    </RowList>
  );
}

Tidak seperti menggunakan Children.map, pendekatan ini tidak membungkus setiap anak secara otomatis. **Namun, pendekatan ini memiliki manfaat yang signifikan dibandingkan dengan contoh sebelumnya dengan Children.map karena pendekatan ini tetap bekerja meskipun Anda terus mengekstrak lebih banyak komponen, sebagai contoh, pendekatan ini tetap bekerja jika Anda mengekstrak komponen MoreRows Anda sendiri:

import { RowList, Row } from './RowList.js';

export default function App() {
  return (
    <RowList>
      <Row>
        <p>Ini adalah item pertama.</p>
      </Row>
      <MoreRows />
    </RowList>
  );
}

function MoreRows() {
  return (
    <>
      <Row>
        <p>Ini adalah item kedua</p>
      </Row>
      <Row>
        <p>Ini adalah item ketiga.</p>
      </Row>
    </>
  );
}

Hal ini tidak akan bekerja dengan Children.map karena fungsi tersebut akan “melihat” <MoreRows /> sebagai satu anak (dan satu baris).

Menerima larik objek sebagai prop

Anda juga bisa secara eksplisit mengoper larik sebagai prop. Sebagai contoh, RowList ini menerima larik baris sebagai prop:

import { RowList, Row } from './RowList.js';

export default function App() {
  return (
    <RowList rows={[
      { id: 'first', content: <p>Ini adalah item pertama.</p> },
      { id: 'second', content: <p>Ini adalah item kedua</p> },
      { id: 'third', content: <p>Ini adalah item ketiga.</p> }
    ]} />
  );
}

Since rows is a regular JavaScript array, the RowList component can use built-in array methods like map on it.

This pattern is especially useful when you want to be able to pass more information as structured data together with children. In the below example, the TabSwitcher component receives an array of objects as the tabs prop:

import TabSwitcher from './TabSwitcher.js';

export default function App() {
  return (
    <TabSwitcher tabs={[
      {
        id: 'first',
        header: 'First',
        content: <p>Ini adalah item pertama.</p>
      },
      {
        id: 'second',
        header: 'Second',
        content: <p>Ini adalah item kedua</p>
      },
      {
        id: 'third',
        header: 'Third',
        content: <p>Ini adalah item ketiga.</p>
      }
    ]} />
  );
}

Unlike passing the children as JSX, this approach lets you associate some extra data like header with each item. Because you are working with the tabs directly, and it is an array, you do not need the Children methods.


Calling a render prop to customize rendering

Instead of producing JSX for every single item, you can also pass a function that returns JSX, and call that function when necessary. In this example, the App component passes a renderContent function to the TabSwitcher component. The TabSwitcher component calls renderContent only for the selected tab:

import TabSwitcher from './TabSwitcher.js';

export default function App() {
  return (
    <TabSwitcher
      tabIds={['first', 'second', 'third']}
      getHeader={tabId => {
        return tabId[0].toUpperCase() + tabId.slice(1);
      }}
      renderContent={tabId => {
        return <p>This is the {tabId} item.</p>;
      }}
    />
  );
}

A prop like renderContent is called a render prop because it is a prop that specifies how to render a piece of the user interface. However, there is nothing special about it: it is a regular prop which happens to be a function.

Render props are functions, so you can pass information to them. For example, this RowList component passes the id and the index of each row to the renderRow render prop, which uses index to highlight even rows:

import { RowList, Row } from './RowList.js';

export default function App() {
  return (
    <RowList
      rowIds={['first', 'second', 'third']}
      renderRow={(id, index) => {
        return (
          <Row isHighlighted={index % 2 === 0}>
            <p>This is the {id} item.</p>
          </Row> 
        );
      }}
    />
  );
}

This is another example of how parent and child components can cooperate without manipulating the children.


Troubleshooting

I pass a custom component, but the Children methods don’t show its render result

Suppose you pass two children to RowList like this:

<RowList>
<p>First item</p>
<MoreRows />
</RowList>

If you do Children.count(children) inside RowList, you will get 2. Even if MoreRows renders 10 different items, or if it returns null, Children.count(children) will still be 2. From the RowList’s perspective, it only “sees” the JSX it has received. It does not “see” the internals of the MoreRows component.

The limitation makes it hard to extract a component. This is why alternatives are preferred to using Children.