Children
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
- Penggunaan
- Alternatif
- Hal ini tidak akan bekerja dengan
Children.map
karena fungsi tersebut akan “melihat”<MoreRows />
sebagai satu anak (dan satu baris). - Troubleshooting
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 propchildren
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 propchildren
yang diterima oleh komponen Anda.fn
: Fungsi yang ingin Anda jalankan untuk setiap anak, serupa dengan metode callback dari larikforEach
. Fungsi ini akan dipanggil dengan anak sebagai argumen pertama dan indeksnya sebagai argumen kedua. Indeks dimulai dari0
dan bertambah pada setiap pemanggilan.- opsional
thisArg
: Nilaithis
yang digunakan untuk memanggil fungsifn
. Jika diabaikan, maka akan menjadiundefined
.
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 propchildren
yang diterima oleh komponen Anda.fn
: Fungsi pemetaan, mirip dengan metode callback dari larikmap
. Fungsi ini akan dipanggil dengan anak sebagai argumen pertama dan indeksnya sebagai argumen kedua. Indeks dimulai dari0
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
: Nilaithis
yang digunakan untuk memanggil fungsifn
. Jika diabaikan, maka akan menjadiundefined
.
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 darichildren
. Jika Anda mengembalikan beberapa elemen darifn
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 propchildren
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
) sebagaichildren
. Dengan kata lain, metode ini memaksakan bahwachildren
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 propchildren
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
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.
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; }
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> ); }
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; }
Alternatif
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
.