Children (Alt Eleman)

Tuzak

Children kullanımı nadirdir ve kırılgan koda yol açabilir. Yaygın alternatiflere bakın.

Children, children prop’u olarak aldığınız JSX’i değiştirmenize ve dönüştürmenize olanak tanır

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

Başvuru Dokümanı

Children.count(children)

Children veri yapısındaki alt eleman sayısını saymak için Children.count(children) öğesini çağırın.

import { Children } from 'react';

function RowList({ children }) {
return (
<>
<h1>Toplam satır: {Children.count(children)}</h1>
...
</>
);
}

Aşağıda daha fazla örneğe bakın.

Parametreler

  • children: Bileşeniniz tarafından alınan children prop değeri.

Returns

Bu children içindeki node’ların sayısı.

Uyarılar

  • Boş node’lar (null, undefined ve Booleans), string’ler, sayılar ve React elemanları ayrı node’lar olarak sayılır. Diziler tek tek node’lar olarak sayılmaz, ancak alt elemanları sayılır. Çaprazlama React öğelerinden daha derine gitmez: bunlar işlenmez ve alt öğeleri çaprazlanmaz. Fragments geçilmez.

Children.forEach(children, fn, thisArg?)

Children veri yapısındaki her alt eleman için bazı kodlar çalıştırmak üzere Children.forEach(children, fn, thisArg?) öğesini çağırın.

import { Children } from 'react';

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

Aşağıda daha fazla örneğe bakın

Parametreler

  • children: Bileşeniniz tarafından alınan children prop değeri.
  • fn: Her çocuk için çalıştırmak istediğiniz işlev, array forEach method callback’e benzer. İlk argüman olarak alt eleman ve ikinci argüman olarak indeksi ile çağrılacaktır. İndeks 0dan başlar ve her çağrıda artar.
  • isteğe bağlı thisArg: fn fonksiyonunun çağrılması gereken this değeri. Atlanırsa, tanımlanmamış olur.

Returns

Children.forEach öğesi undefined döndürür.

Uyarılar

  • Boş node’lar (null, undefined ve Booleans), string’ler, sayılar ve React elements ayrı node’lar olarak sayılır. Diziler tek tek node’lar olarak sayılmaz, ancak alt elemanları sayılır. Çaprazlama React öğelerinden daha derine gitmez: bunlar işlenmez ve alt öğeleri çaprazlanmaz. Fragments çaprazlanmaz.

Children.map(children, fn, thisArg?)

Alt eleman veri yapısındaki her alt elemani eşlemek veya dönüştürmek için Children.map(children, fn, thisArg?) öğesini çağırın.

import { Children } from 'react';

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

Aşağıda daha fazla örneğe bakınız.

Parameters

  • children: Bileşeniniz tarafından alınan children prop değeri.
  • fn: array map metodu callback’ine benzer eşleme fonksiyonu. İlk argüman olarak child’ı, ikinci argüman olarak indeksini alır. İndeks 0’dan başlar ve her çağrıda artar. Bu fonksiyondan bir React node döndürmeniz gerekir. Bu; boş bir node (null, undefined veya Boolean), bir string, bir number, bir React elementi ya da diğer React node’larından oluşan bir array olabilir.
  • optional thisArg: fn fonksiyonunun çağrılacağı this değeri. Eğer verilmezse undefined olur.

Returns

Eğer children null veya undefined ise, aynı değeri döndürür.

Aksi takdirde, fn fonksiyonundan döndürdüğünüz node’lardan oluşan düz (flat) bir array döndürür. Dönen array, null ve undefined hariç tüm döndürdüğünüz node’ları içerir.

Uyarılar

  • Boş node’lar (null, undefined ve Boolean’lar), string’ler, number’lar ve React elementleri ayrı birer node olarak sayılır. Array’ler tekil node olarak sayılmaz, ancak içlerindeki çocuklar sayılır. Traversal (gezme) React elementlerinin ötesine geçmez: render edilmezler ve içlerindeki çocuklar da traverse edilmez. Fragments da traverse edilmez.

  • fn fonksiyonundan key’li bir element veya element array’i döndürürseniz, döndürülen elementlerin key’leri, children içindeki karşılık gelen orijinal item’ın key’i ile otomatik olarak birleştirilir. fn içinden birden fazla elementi array olarak döndürdüğünüzde, bu elementlerin key’lerinin yalnızca kendi aralarında lokal olarak benzersiz olması yeterlidir.


Children.only(children)

Alt elemanların tek bir React öğesini temsil ettiğini doğrulamak için Children.only(children) öğesini çağırın.

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

Parametreler

  • children: Bileşeniniz tarafından alınan children prop değeri.

Returns

Eğer children geçerli bir eleman ise, bu elemanı döndürür.

Aksi takdirde hata verir.

Uyarılar

  • Bu yöntem children olarak bir dizi (örneğin, Children.map’in dönüş değeri) geçirirseniz her zaman hata fırlatır. Başka bir deyişle, children’ın tek bir React öğesi olmasını zorunlu kılar, ancak bu bir öğe içeren bir dizi olması anlamına gelmez.

Children.toArray(children)

Alt eleman veri yapısından bir dizi oluşturmak için Children.toArray(çocuklar) öğesini çağırın.

import { Children } from 'react';

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

Parametreler

  • children: Bileşeniniz tarafından alınan children prop değeri.

Returns

children içindeki elemanların düz bir dizisini döndürür.

Uyarılar

  • Boş node’lar (null, undefined ve Booleans) döndürülen dizide atlanacaktır. Döndürülen öğelerin anahtarları, orijinal öğelerin anahtarlarından, iç içe geçme düzeylerinden ve konumlarından hesaplanacaktır. Bu, dizinin düzleştirilmesinin davranışta değişikliklere yol açmamasını sağlar.

Kullanım

Children’ı dönüştürmek

Bileşeninizin [children propu olarak aldığı](/learn/passing-props-to-a-component#passing-jsx-as-children) JSX çocuklarını dönüştürmek için Children.map` çağrısını yapın:

import { Children } from 'react';

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

Yukarıdaki örnekte, RowList aldığı her children’ı bir <div className=“Row”> konteynerine sarar. Örneğin, ana bileşenin RowList öğesine children prop’u olarak üç <p> etiketi ilettiğini varsayalım:

<RowList>
<p>This is the first item.</p>
<p>This is the second item.</p>
<p>This is the third item.</p>
</RowList>

Daha sonra, yukarıdaki RowList implementasyonu ile birlikte, son render edilmiş sonuç şu şekilde görünecektir:

<div className="RowList">
<div className="Row">
<p>This is the first item.</p>
</div>
<div className="Row">
<p>This is the second item.</p>
</div>
<div className="Row">
<p>This is the third item.</p>
</div>
</div>

Children.map, array’leri map() ile dönüştürmeye benzer. Aradaki fark, children veri yapısının opaque (şeffaf olmayan) olarak kabul edilmesidir. Bu, bazen bir array olsa bile onun bir array ya da başka bir veri tipi olduğunu varsaymamanız gerektiği anlamına gelir. Bu yüzden, children üzerinde dönüşüm yapmanız gerekiyorsa Children.map kullanmalısınız.

import { Children } from 'react';

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

Derinlemesine İnceleme

children prop neden her zaman bir array değildir?

React’te children prop’u opaque (şeffaf olmayan) bir veri yapısı olarak kabul edilir. Bu, onun nasıl yapılandırıldığına güvenmemeniz gerektiği anlamına gelir. children üzerinde transform, filtreleme veya sayma işlemleri yapmak için Children metodlarını kullanmalısınız.

Pratikte children veri yapısı çoğu zaman içeride bir array olarak temsil edilir. Ancak yalnızca tek bir child varsa, React ekstra bir array oluşturmaz; çünkü bu gereksiz bellek kullanımına yol açar. Siz children’ın yapısına doğrudan erişmek yerine Children metodlarını kullandığınız sürece, React’in iç implementasyonu değişse bile kodunuz bozulmaz.

children bir array olsa bile Children.map bazı özel davranışlar sunar. Örneğin Children.map, dönen elementlerin key değerlerini, verilen children içindeki key’lerle birleştirir. Bu sayede, JSX children’lar wrapper’lara sarılsa bile orijinal key’lerini “kaybetmez”.

Tuzak

children veri yapısı, JSX olarak geçirdiğiniz bileşenlerin render edilmiş çıktısını içermez. Aşağıdaki örnekte RowList tarafından alınan children yalnızca üç değil, iki öğe içerir:

  1. <p>This is the first item.</p>
  2. <MoreRows />

Bu nedenle bu örnekte yalnızca iki row wrapper oluşturulur:

import RowList from './RowList.js';

export default function App() {
  return (
    <RowList>
      <p>This is the first item.</p>
      <MoreRows />
    </RowList>
  );
}

function MoreRows() {
  return (
    <>
      <p>This is the second item.</p>
      <p>This is the third item.</p>
    </>
  );
}

<MoreRows /> gibi iç bileşenlerin render edilmiş çıktısını children üzerinde işlem yaparak elde etmenin hiçbir yolu yoktur. Bu yüzden genellikle alternatif çözümlerden birini kullanmak daha iyidir.


Her child için kod çalıştırma

Children.forEach fonksiyonunu, children veri yapısındaki her child üzerinde gezinmek için çağırabilirsiniz. Herhangi bir değer döndürmez ve array forEach metoduna benzer. Kendi array’inizi oluşturmak gibi özel mantıkları çalıştırmak için kullanılabilir.

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(); // Remove the last separator
  return result;
}

Tuzak

Daha önce de belirtildiği gibi, children üzerinde işlem yaparken iç bir bileşenin render edilmiş çıktısını elde etmenin hiçbir yolu yoktur. Bu yüzden genellikle alternatif çözümlerden birini kullanmak daha iyidir.


Counting children

Children.count(children) fonksiyonunu çağırarak children sayısını hesaplayabilirsiniz.

import { Children } from 'react';

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

Tuzak

Daha önce de belirtildiği gibi, children üzerinde işlem yaparken iç bir bileşenin render edilmiş çıktısını elde etmenin hiçbir yolu yoktur. Bu yüzden genellikle alternatif çözümlerden birini kullanmak daha iyidir.


Children’ı array’e dönüştürme

Children.toArray(children) fonksiyonunu çağırarak children veri yapısını normal bir JavaScript array’ine dönüştürebilirsiniz. Bu sayede, filter, sort veya reverse gibi yerleşik array metodlarını kullanarak üzerinde işlem yapabilirsiniz.

import { Children } from 'react';

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

Tuzak

Daha önce de belirtildiği gibi, children üzerinde işlem yaparken iç bir bileşenin render edilmiş çıktısını elde etmenin hiçbir yolu yoktur. Bu yüzden genellikle alternatif çözümlerden birini kullanmak daha iyidir.


Alternatifler

Not

Bu bölüm, şu şekilde import edilen Children API’sine (büyük C ile yazılan) alternatifleri açıklar:

import { Children } from 'react';

Bunu, JSX’i children prop’u olarak kullanmakla (küçük c), karıştırmayın; bu kullanım doğrudur ve önerilir.

Birden fazla bileşen sunma

Children metodlarıyla children üzerinde işlem yapmak genellikle kırılgan (fragile) kodlara yol açar. JSX içinde bir bileşene children verdiğinizde, genellikle o bileşenin bu children’ları tek tek manipüle etmesini veya dönüştürmesini beklemezsiniz.

Mümkün olduğunda Children metodlarını kullanmaktan kaçınmaya çalışın. Örneğin, RowList içindeki her child’ı <div className="Row"> ile sarmalamak istiyorsanız, bir Row bileşeni export edin ve her satırı manuel olarak onunla sarmalayın:

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

export default function App() {
  return (
    <RowList>
      <Row>
        <p>This is the first item.</p>
      </Row>
      <Row>
        <p>This is the second item.</p>
      </Row>
      <Row>
        <p>This is the third item.</p>
      </Row>
    </RowList>
  );
}

Children.map kullanmaktan farklı olarak, bu yaklaşım her child’ı otomatik olarak sarmalamaz. Ancak, bu yaklaşımın Children.map ile yapılan önceki örneğe kıyasla önemli bir avantajı vardır: daha fazla bileşen çıkarsanız (extract etseniz) bile çalışmaya devam eder. Örneğin, kendi MoreRows bileşeninizi çıkarsanız bile hâlâ çalışır:

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

export default function App() {
  return (
    <RowList>
      <Row>
        <p>This is the first item.</p>
      </Row>
      <MoreRows />
    </RowList>
  );
}

function MoreRows() {
  return (
    <>
      <Row>
        <p>This is the second item.</p>
      </Row>
      <Row>
        <p>This is the third item.</p>
      </Row>
    </>
  );
}

Bu yaklaşım Children.map ile çalışmaz çünkü <MoreRows />’u tek bir child (ve tek bir row) olarak “görür”.


Prop olarak object array kabul etme

Ayrıca bir array’i açıkça prop olarak geçebilirsiniz. Örneğin, bu RowList bir rows array’ini prop olarak kabul eder:

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

export default function App() {
  return (
    <RowList rows={[
      { id: 'first', content: <p>This is the first item.</p> },
      { id: 'second', content: <p>This is the second item.</p> },
      { id: 'third', content: <p>This is the third item.</p> }
    ]} />
  );
}

rows normal bir JavaScript array olduğu için, RowList bileşeni üzerinde map gibi yerleşik array metodlarını kullanabilir.

Bu pattern, children ile birlikte daha fazla bilgiyi yapılandırılmış veri olarak geçmek istediğiniz durumlarda özellikle kullanışlıdır. Aşağıdaki örnekte, TabSwitcher bileşeni tabs prop’u olarak object’lerden oluşan bir array alır:

import TabSwitcher from './TabSwitcher.js';

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

JSX olarak children geçirmekten farklı olarak, bu yaklaşım her bir öğeye header gibi ekstra verileri ilişkilendirmenize izin verir. tabs verisiyle doğrudan çalıştığınız ve bu bir array olduğu için Children metodlarına ihtiyaç duymazsınız.


Render prop çağırarak render’ı özelleştirme

Her bir öğe için JSX üretmek yerine, JSX döndüren bir fonksiyon da geçebilir ve bunu gerektiğinde çağırabilirsiniz. Bu örnekte, App bileşeni TabSwitcher bileşenine bir renderContent fonksiyonu geçirir. TabSwitcher ise bu fonksiyonu yalnızca seçili tab için çağırır:

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

renderContent gibi bir prop’a render prop denir çünkü kullanıcı arayüzünün bir parçasının nasıl render edileceğini belirten bir prop’tur. Ancak bunda özel bir durum yoktur: sadece fonksiyon olan normal bir prop’tur.

Render prop’lar fonksiyon olduğu için onlara bilgi de geçebilirsiniz. Örneğin, bu RowList bileşeni her row’un id ve index değerini renderRow render prop’una geçirir ve renderRow bu index değerini kullanarak çift satırları highlight eder:

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

Bu, parent ve child bileşenlerin children’ları manipulate etmeden birlikte nasıl çalışabileceğine dair başka bir örnektir.


Sorun giderme

Özel bir bileşen geçiriyorum ama Children metodları onun render sonucunu göstermiyor

Diyelim ki RowList bileşenine şu şekilde iki child geçiriyorsunuz:

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

Eğer RowList içinde Children.count(children) kullanırsanız 2 sonucunu alırsınız. MoreRows 10 farklı item render etse bile ya da null döndürse bile, Children.count(children) yine 2 olur. RowList açısından bakıldığında sadece kendisine gelen JSX’i “görür”. MoreRows bileşeninin iç detaylarını “göremez”.

Bu kısıtlama, bir bileşeni extract etmeyi zorlaştırır. Bu yüzden Children kullanmak yerine alternatifler tercih edilir.