Listeler ve Anahtarlar

Öncelikle, listelerin JavaScript’te nasıl dönüştürüldüğünü gözden geçirelim.

Aşağıdaki kod göz önüne alındığında, sayılardan oluşan bir diziyi almak ve değerlerini iki katına çıkarmak için map() fonksiyonunu kullanırız. map() tarafından döndürülen yeni diziyi doubled değişkenine atayıp ekrana yazdırırız:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

Bu kod konsol ekranına [2, 4, 6, 8, 10] yazdırır.

React’te, dizileri element listelerine dönüştürmek de neredeyse aynıdır.

Çoklu Bileşenleri Render Etmek

Elementlerden koleksiyonlar oluşturabilir ve bu koleksiyonları küme parentezlerini {} kullanarak JSX’e dahil edebilirsiniz.

Aşağıda, Javascript’in map() fonksiyonunu kullanarak numbers dizisinin içinde geziyoruz. Her bir element için bir <li> elemanı dönüyoruz. Son olarak da, ortaya çıkan diziyi listItems a atıyoruz:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

listItems dizisinin tamamını bir <ul> elemanının içine ekliyoruz, ve DOM’a render ediyoruz:

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

CodePen’de Deneyin

Bu kod, 1 ile 5 arasındaki sayıların madde işaretli listesini görüntüler.

Temel Liste Bileşeni

Genellikle listeleri bir bileşenin içinde render edersiniz.

Bir önceki örneği, bir sayı dizisini kabul eden ve bir öğe listesi çıktısı veren bir bileşende yeniden düzenleyebiliriz.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Bu kodu çalıştırdığınızda, liste elemanları için bir anahtar verilmesi gerektiği konusunda size bir uyarı verilir. Bir “anahtar”, öğe listeleri oluştururken eklemeniz gereken bir string özelliğidir. Bunun neden önemli olduğunu bir sonraki bölümde inceleyeceğiz.

numbers.map() içindeki liste elemanlarına birer anahtar atayalım ve eksik anahtar sorununu düzeltelim:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

CodePen’de Deneyin

Anahtarlar

Anahtarlar; hangi öğelerin değiştiğini, eklendiğini ya da silindiğini belirleme noktasında React’e yardımcı olur:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

Bir anahtar seçmenin en iyi yolu, kardeşleri arasında bir liste öğesini benzersiz olarak tanımlayan bir string kullanmaktır. Çoğu zaman verinizin içindeki ID’leri anahtar olarak kullanırsınız:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

Render edilen öğeleriniz için sabit ID’leriniz yoksa, son çare olarak, öğenin index numarasını anahtar olarak kullanabilirsiniz:

const todoItems = todos.map((todo, index) =>
  // Bunu yalnızca öğelerinizin sabit ID'leri yoksa yapın
  <li key={index}>
    {todo.text}
  </li>
);

Dizi içindeki elemanların değişme ihtimali varsa, anahtarlar için index numaralarının kullanılmasını önermiyoruz. Bu, performansı olumsuz yönde etkileyebilir ve bileşen state’i ile ilgili sorunlara neden olabilir. Index numarasının anahtar olarak kullanılmasının olumsuz etkilerine dair detaylı açıklama için Robin Pokorny’nin makalesine göz atın. Öğeleri listelemek için belirgin bir anahtar atamamayı seçtiğinizde, React varsayılan olarak index numaralarını anahtar olarak kullanacaktır.

Daha fazla bilgi edinmek istiyorsanız, işte size neden anahtarların gerekli olduğuna dair detaylı bir açıklama.

Anahtarları Olan Bileşenleri Çıkarmak

Anahtarlar yalnızca çevreleyen dizinin bağlamında anlamlıdır.

Örneğin, bir ListItem bileşenini çıkarırsanız, anahtarı ListItem‘in içindeki <li> öğesinden ziyade, dizinin içindeki <ListItem /> öğelerinde tutmalısınız.

Örnek: Yanlış Anahtar Kullanımı

function ListItem(props) {
  const value = props.value;
  return (
    // Yanlış! Anahtarı burada belirtmeye gerek yok:
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Yanlış! Anahtar burada tanımlanmalıydı:
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Örnek: Doğru Anahtar Kullanımı

function ListItem(props) {
  // Doğru! Anahtarı burada belirtmeye gerek yok:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Doğru! Anahtar dizinin içinde belirtilmelidir:
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

CodePen’de deneyin

Temel bir kural da map() çağrısının içindeki elemanların anahtarlara ihtiyaç duymasıdır.

Anahtarlar Sadece Kardeşler Arasında Benzersiz Olmalıdır

Dizilerde kullanılan anahtarlar kardeşleri arasında benzersiz olmalıdır. Ancak, küresel olarak (uygulama genelinde) benzersiz olmaları gerekmez. İki farklı dizi ürettiğimizde aynı anahtarları kullanabiliriz:

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'Merhaba Dünya', content: 'React Öğrenmeye Hoşgeldiniz!'},
  {id: 2, title: 'Kurulum', content: 'React\'i npm üzerinden kurabilirsiniz.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

CodePen’de Deneyin

Anahtarlar, React’e bir ipucu olarak hizmet eder, ancak bileşenlerinize aktarılmazlar. Bileşeninizde aynı değere ihtiyacınız varsa, belirgin bir şekilde farklı bir ada sahip bir prop olarak iletin:

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

Yukarıdaki örnekte, Post bileşeni props.id yi okuyabilir, ancak props.key i okuyamaz.

map() i JSX’e gömmek

Yukarıdaki örneklerde ayrı bir listItems değişkeni tanımladık ve JSX’e dahil ettik:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

JSX, herhangi bir ifadeyi küme parantezlerine yerleştirmeye izin verir, böylece map () sonucunu satır içi olarak ekleyebiliriz:

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

CodePen’de Deneyin

Bazen bu yöntem daha temiz bir kodla sonuçlanır; ancak bu tarz da kötüye kullanılabilir. JavaScript’te olduğu gibi, okunabilirlik için, bir değişken çıkarmaya değip değmeyeceğine karar vermek size kalmıştır. Map () gövdesi çok fazla iç içe geçmişse, bir bileşen çıkarmak için iyi bir zaman olabileceğini unutmayın.