---
title: Gezinme
source: 'https://academia.sh/tr/kurslar/react-native/gezinme'
course: 'React Native'
language: tr
updated: '2026-10-21T05:02:53+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yığın, sekme ve çekmece gezinmesini rota ve geri yığını kavramlarıyla açıklar'
    - 'Yeni rota itmenin ve geri dönmenin görünüm ağacında hangi düğümleri kurup söktüğünü ölçer'
    - 'Alttaki ekranın yeni rota itilince neden korunan çıktığını gösterir'
    - 'Görünmeyen sekmenin ağaçta kalıp kalmamasının akıbeti nasıl değiştirdiğini karşılaştırır'
---

# Gezinme

Gezinme, uygulamanın ekranlarını yığın, sekme ya da çekmece olarak düzenler. Ders yeni bir rota itilince ve geri dönülünce görünüm ağacındaki düğümlerin akıbetini ölçer: alttaki ekran korunan kalır.

Önceki ders, tek platformda doğan bir anahtarın ortak kodun içinde nasıl durduğunu ele aldı. Bu dersten itibaren kurs tek ekranlı örneklerden çıkar ve uygulamanın katmanlarına geçer. İlk katman gezinmedir: kullanıcı bir ekrandan ötekine nasıl geçer ve geçerken eski ekrana ne olur.

Kursun sorusu ders boyunca değişmez: **bu güncelleme görünüm ağacındaki düğüme ne yapıyor?** Yanıtın dört biçimi var. Düğüm aynı kalır ve özellikleri de aynıysa **korunan**dır. Düğüm aynı kalır ama bir özelliği değişirse **güncellenen**dir. Düğüm ağaçta ilk kez belirirse **kurulan**, ağaçtan çıkarsa **sökülen**dir. Güncellenen, kurulan ve sökülen düğümlerin toplamına komut denir: çerçevenin yerel tarafa göndermesi gereken iş budur. Akıbet elle atanmaz. Aşağıdaki çekirdek iki ağacı karşılaştırır ve her düğümün akıbetini kural verir.

```javascript
// fate.mjs — bir guncellemenin gorunum agacindaki her dugume ne yaptigini siniflandirir
export const FATES = ["korunan", "guncellenen", "kurulan", "sokulen"];

export function el(type, props = {}, children = [], key = null) {
  return { type, props, children, key };
}

function segment(node) {
  return node.key === null ? node.type : `${node.type}[${node.key}]`;
}

function identity(node, index) {
  return node.key === null ? `#${index}` : `key:${node.key}`;
}

function sameProps(a, b) {
  const names = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort();
  return names.every((n) => JSON.stringify(a[n]) === JSON.stringify(b[n]));
}

function whole(node, path, fate, ops) {
  const here = `${path}/${segment(node)}`;
  ops.push({ fate, path: here });
  node.children.forEach((child) => whole(child, here, fate, ops));
}

export function reconcile(prev, next, path = "", ops = []) {
  if (prev === null) {
    whole(next, path, "kurulan", ops);
    return ops;
  }
  if (next === null) {
    whole(prev, path, "sokulen", ops);
    return ops;
  }
  if (prev.type !== next.type || prev.key !== next.key) {
    whole(prev, path, "sokulen", ops);
    whole(next, path, "kurulan", ops);
    return ops;
  }
  const here = `${path}/${segment(next)}`;
  ops.push({ fate: sameProps(prev.props, next.props) ? "korunan" : "guncellenen", path: here });
  const before = new Map(prev.children.map((child, i) => [identity(child, i), child]));
  const matched = new Set();
  next.children.forEach((child, i) => {
    const id = identity(child, i);
    matched.add(id);
    reconcile(before.has(id) ? before.get(id) : null, child, here, ops);
  });
  prev.children.forEach((child, i) => {
    if (!matched.has(identity(child, i))) reconcile(child, null, here, ops);
  });
  return ops;
}

export function printOps(ops) {
  ops.forEach((op) => console.log(`${op.fate}: ${op.path}`));
}

export function countFates(ops) {
  for (const name of FATES) {
    console.log(`${name}: ${ops.filter((op) => op.fate === name).length}`);
  }
  console.log(`komut: ${ops.filter((op) => op.fate !== "korunan").length}`);
}
```

Kural, alt ağaç yalnız sonraki ağaçtaysa kurulan, yalnız öncekindeyse sökülen der. Tip ya da anahtar farklıysa eski düğümün tamamı sökülen, yenisinin tamamı kurulandır. Aksi hâlde özellikleri karşılaştırır; çocukları anahtarla ya da sırayla eşler. Model bu akıbetin kuralını kurar; model çerçevenin kendisi değildir.

## Yığın: Rota İtmek ve Geri Dönmek

Gezinmenin en yaygın biçimi yığındır. Her ekran bir **rota**ya karşılık gelir: rota ekranın adıdır. Açık rotaların sıralı listesine **geri yığını** denir. Kullanıcı bir satıra dokununca yeni rota yığının sonuna itilir; geri düğmesine basınca son rota çıkarılır. Yığın gezinme kitaplığı bu listeyi tutar ve her rota için bir ekran kurar. Uygulama yazarının işi, rotaları ve hangi ekrana gideceklerini tanımlamaktır.

```jsx
// Platform kodu: RootStack
function RootStack() {
  return (
    <Stack>
      <Screen name="liste" component={ListScreen} />
      <Screen name="detay" component={DetailScreen} />
    </Stack>
  );
}
```

Bu parça ölçülmez; model kitaplığı çalıştırmaz. Modelde yığın, rota adlarının listesidir ve `renderStack` her rotayı, rota adıyla anahtarlanmış bir `Screen` düğümüne çevirir. Anahtar önemlidir: aynı adlı rota iki ağaçta aynı ekran sayılır.

**UK1.** Model, yığındaki her rotanın ekranını görünüm ağacında tutar; üstte kalan rota alttakini örtse de alttaki ekranın düğümü ağaçtan çıkmaz. Gerçek kitaplığın bu seçimi nasıl yaptığı kitaplığa bağlıdır; model bir seçim yapar ve bunu açıkça söyler.

```javascript
// stack.mjs — gezinme yiginin rotalarindan gorunum agaci kurar
import { el } from "./fate.mjs";

export function renderStack(routes) {
  return el("Stack", {}, routes.map((name) =>
    el("Screen", { baslik: name }, [el("Text", { metin: name })], name)));
}
```

Önce liste ekranındayız ve bir satıra dokunuyoruz. Yığın `liste` rotasından `liste`, `detay` rotalarına geçer.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderStack } from "./stack.mjs";

const ops = reconcile(renderStack(["liste"]), renderStack(["liste", "detay"]));
printOps(ops);
countFates(ops);
```

```text
korunan: /Stack
korunan: /Stack/Screen[liste]
korunan: /Stack/Screen[liste]/Text
kurulan: /Stack/Screen[detay]
kurulan: /Stack/Screen[detay]/Text
korunan: 3
guncellenen: 0
kurulan: 2
sokulen: 0
komut: 2
```

Yeni rota itildiğinde `detay` ekranı ve içindeki metin kurulandır: iki düğüm. Alttaki `/Stack/Screen[liste]` korunandır, çünkü özellikleri değişmedi ve anahtarı aynı kaldı. Komut sayısı yalnız yeni ekranın düğümlerini sayar. Kural uygulamanın ne kadar ekranı olduğuna değil, bu güncellemede hangi düğümün değiştiğine bakar.

Geri dönüş aynı kuralın tersidir. Üç ekranlı bir yığından bir rota çıkarılır; odak satırı, yani dönülen ekran, ayrıca yazdırılır.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderStack } from "./stack.mjs";

const ops = reconcile(
  renderStack(["liste", "detay", "not"]),
  renderStack(["liste", "detay"]),
);
printOps(ops.filter((op) => op.path === "/Stack/Screen[detay]"));
countFates(ops);
```

```text
korunan: /Stack/Screen[detay]
korunan: 5
guncellenen: 0
kurulan: 0
sokulen: 2
komut: 2
```

Geri dönülen `detay` ekranı korunandır, çıkarılan `not` ekranı ve metni sökülendir. Sökülen bir ekranın durumu, yani üzerinde yazılmış bir giriş ya da kaydırma konumu, düğümle birlikte yok olur. Geri dönüp aynı rotaya yeniden gidildiğinde ekran yeniden kurulur. Bu yüzden ekran kapanırken kaybolmaması gereken bilgi ekranın dışında, sonraki derslerde ele alınan katmanlarda durur.

## Rotayı Değiştirmek

Gezinmede bir de değiştirme vardır: yığının son rotası çıkarılır ve yerine başka bir rota konur. Bir ürün sayfasından başka bir ürün sayfasına geçmek bunun örneğidir. Ekranın kodu aynıdır, yalnız hangi ürünü gösterdiği değişir. Hangi ürünün gösterildiği rotaya parametre olarak girer.

**UK3.** Model rota adını ve parametresini tek anahtarda birleştirir: `urun-1` ve `urun-2` iki ayrı rotadır. Gerçek kitaplıklar anahtarı çoğunlukla rota adından ve kimliğinden kurar; model bu birleşimi tek dizgeye indirir.

```javascript
// main.mjs
import { reconcile, printOps } from "./fate.mjs";
import { renderStack } from "./stack.mjs";

printOps(reconcile(renderStack(["liste", "urun-1"]), renderStack(["liste", "urun-2"])));
```

```text
korunan: /Stack
korunan: /Stack/Screen[liste]
korunan: /Stack/Screen[liste]/Text
kurulan: /Stack/Screen[urun-2]
kurulan: /Stack/Screen[urun-2]/Text
sokulen: /Stack/Screen[urun-1]
sokulen: /Stack/Screen[urun-1]/Text
```

Anahtar farklı olduğu için `urun-1` ekranı metniyle birlikte sökülür, `urun-2` ekranı metniyle birlikte kurulur; `liste` korunandır. Ekran tipi aynı olsa da kural düğümleri anahtarla eşler, bu yüzden iki ürün sayfası aynı düğüm sayılmaz. Sonuç kullanıcıya şöyle yansır: birinci ürün sayfasında kaydırılmış konum ya da yazılmış bir not ikinci ürüne taşınmaz. Taşınması isteniyorsa ekranın kimliği rota adı olur ve ürün bilgisi özellik olarak girer; o durumda aynı düğüm güncellenen olurdu. Hangisinin doğru olduğu uygulama özelliğine bağlıdır ve kural bu kararı vermez.

## Sekme ve Çekmece

Sekme gezinmesinde rotalar bir yığın oluşturmaz, kardeştir: kullanıcı bir sekme çubuğundan birini seçer ve yalnız o sekmenin ekranı görünür. Çekmece gezinmesi aynı fikrin kenardan açılan biçimidir; rotalar kardeştir, seçimi çubuk yerine bir menü yapar. Üçünün gezinme olarak farkı geri yığınındadır; görünüm ağacı açısından asıl soru başka: görünmeyen sekmenin ekranı ağaçta kalıyor mu?

**UK2.** Bu soruyu model iki seçenekle ölçer. Birinde görünmeyen sekmeler ağaçta durur ve yalnız görünürlük özelliği değişir. Öteki seçenekte yalnız seçili sekme ağaçtadır. Gerçek kitaplıklar bu iki davranıştan birini varsayılan sunar ve çoğu ayar olarak değiştirmeye izin verir; model hangisinin varsayılan olduğunu söylemez.

```javascript
// tabs.mjs — sekme cubugunun gorunum agacini kurar; saklayan secenek gizli sekmeyi agacta tutar
import { el } from "./fate.mjs";

export function renderTabs(active, names, keepHidden) {
  const shown = keepHidden ? names : names.filter((name) => name === active);
  return el("Tabs", {}, shown.map((name) =>
    el("Screen", { gorunen: name === active }, [el("Text", { metin: name })], name)));
}
```

Kullanıcı `ana` sekmesinden `ara` sekmesine geçiyor. İki seçenek aynı geçişi yaşar ve yalnız akıbet sayıları karşılaştırılır.

```javascript
// main.mjs
import { reconcile, countFates } from "./fate.mjs";
import { renderTabs } from "./tabs.mjs";

const names = ["ana", "ara", "profil"];
console.log("saklayan:");
countFates(reconcile(renderTabs("ana", names, true), renderTabs("ara", names, true)));
console.log("saklamayan:");
countFates(reconcile(renderTabs("ana", names, false), renderTabs("ara", names, false)));
```

```text
saklayan:
korunan: 5
guncellenen: 2
kurulan: 0
sokulen: 0
komut: 2
saklamayan:
korunan: 1
guncellenen: 0
kurulan: 2
sokulen: 2
komut: 4
```

Saklayan seçenekte iki ekran güncellenendir: biri görünür olur, öteki görünmez. Metin düğümleri ve üçüncü sekme korunandır. Saklamayan seçenekte `ana` ekranı sökülür, `ara` ekranı kurulur; her biri metniyle birlikte iki düğümdür. Aynı geçiş, iki seçenekte iki ayrı akıbet dağılımı verir. Saklayan seçenek sekmeye dönüldüğünde durumu korur ama ağaçta görünmeyen ekranların maliyetini taşır. Saklamayan seçenek ağacı küçük tutar ve geri dönüşte ekranı baştan kurar.

## Kaynak Parçayı Satır Satır Okumak

Yukarıdaki yığın tanımı kısadır ama dört ayrı karar taşır. İlk karar, `Stack` kapsayıcısının kendisidir: ekranlar bir yığının çocuğu olarak tanımlanır, yani aralarındaki ilişki sıradır. İkinci karar, her `Screen` satırındaki `name` değeridir. Bu ad rotanın kimliğidir; ağaçta anahtara dönüşen şey de odur. Üçüncü karar, `component` satırıdır: rota yalnızca bir ad değil, o adla açılacak ekranın tanımıdır. Dördüncü karar, tanımların sırasıdır: ilk tanımlanan rota başlangıç ekranı olur, ötekilere ancak bir geçişle varılır.

Bu satırlardan hiçbiri bir düğüm kurmaz. Tanım, ekranların hangi adla var olabileceğini söyler; hangisinin şu an açık olduğunu söylemez. Açık olanlar yığının çalışma anındaki içeriğidir: rota listesi. Ağaç bu listeden türer ve kural, liste değişince ağacın ne yaptığını sınıflar. Tanımı değiştirmek ile yığını değiştirmek bu yüzden farklı işlerdir: ilki uygulamanın kodunu, ikincisi kullanıcının o anki yolunu etkiler.

## Yığın Derinleştikçe

Kullanıcı bir listeden ayrıntıya, ayrıntıdan bir alt ayrıntıya iner. Her adımda yığına bir rota eklenir. Bu ölçümde itme alttaki ekranları korunan bıraktı ve yalnız yeni ekranın düğümlerini kurdu. Bu, gezinmeyi ucuz gösterir: bir adımın maliyeti, yeni ekranın büyüklüğüyle sınırlıdır, yığının uzunluğuyla değil.

Ama aynı sonucun bir bedeli vardır. Alttaki ekranlar ağaçta durduğu için her biri düğümlerini, durumunu ve yerel görünümünü taşımaya devam eder. Yığın derinleştikçe ağaç büyür. Kullanıcının geri dönüşte kaldığı yeri bulması bu seçimin kazancıdır; ağacın büyümesi bedelidir. Bir uygulama çok derin gezinmeye izin veriyorsa kazancın bedelini bilerek ödemesi gerekir. Gezinmeyi tasarlarken sorulacak soru "geri dönülebilir mi?" kadar "geri dönüldüğünde hangi durum duruyor olmalı?" sorusudur.

Rotayı değiştirmek bu dengeyi değiştirir. Değiştirme ölçümünde eski ekran söküldü, yenisi kuruldu ve eski ekranın durumu yok oldu. Kullanıcı bir ürünün ayrıntısından başka bir ürünün ayrıntısına geçiyorsa bu çoğu zaman istenen davranıştır: iki ürünün kaydırma konumunu paylaşması anlamsızdır. Aynı davranış, kullanıcı aynı ürüne dönmek istediğinde bir kayıptır. Hangi davranışın doğru olduğunu akıbet söylemez; akıbet yalnız hangisinin olduğunu söyler.

## Sınırlayıcı Ölçüm

Yığında alttaki ekranın korunan çıkması gezinmenin kendisinden değil, modelin bir varsayımından gelir: UK1, alttaki ekranın özelliğine örtüldüğünü yazmıyor. Bir kitaplık alttaki ekrana `ustte` gibi bir özellik taşısaydı, aynı itme başka bir akıbet verirdi. Aşağıda aynı itme iki ağaç kuruluşuyla ölçülür.

```javascript
// main.mjs
import { el, reconcile, printOps, countFates } from "./fate.mjs";
import { renderStack } from "./stack.mjs";

function renderMarked(routes) {
  return el("Stack", {}, routes.map((name, i) =>
    el("Screen", { ustte: i === routes.length - 1 }, [el("Text", { metin: name })], name)));
}

const focus = (op) => op.path === "/Stack/Screen[liste]";
const plain = reconcile(renderStack(["liste"]), renderStack(["liste", "detay"]));
const marked = reconcile(renderMarked(["liste"]), renderMarked(["liste", "detay"]));
console.log("isaretsiz:");
printOps(plain.filter(focus));
console.log("isaretli:");
printOps(marked.filter(focus));
countFates(marked);
```

```text
isaretsiz:
korunan: /Stack/Screen[liste]
isaretli:
guncellenen: /Stack/Screen[liste]
korunan: 2
guncellenen: 1
kurulan: 2
sokulen: 0
komut: 3
```

Aynı itme, ağacın kurulum biçimine göre `/Stack/Screen[liste]` düğümünü korunan ya da güncellenen yaptı. Kural ekranın örtüldüğünü görmez; yalnız ağaçtaki özelliğin değiştiğini görür. Örtülme bilgisi ağaca özellik olarak yazılıyorsa her itme alttaki ekran için bir komut doğurur. Bu yüzden kitaplığın örtülmeyi nasıl bildirdiği, gezinme maliyetinin bir parçasıdır ve kural bu kararı vermez; ders bunu düzyazıda söyler.

## Yaygın Yanılgılar

- "Geri dönmek önceki ekranı yeniden kurar." Geri dönme ölçümünde önceki ekranın düğümleri korunan çıktı; sökülen yalnızca çıkarılan rotanın ekranıydı. Yeniden kurulan bir şey olmadığı için kaydırma konumu da yerinde kalır.
- "Yığındaki her ekran ağaçtan çıkarılabilir, kullanıcı fark etmez." Alttaki ekran ağaçtan çıkarılırsa durumu da gider. Kullanıcı geri döndüğünde ekran sıfırdan kurulur ve yarım kalan iş kaybolur.
- "Rota adı yeterli kimliktir." Aynı ad farklı parametrelerle iki kez açılabiliyorsa ad tek başına anahtar olamaz; model bu yüzden adı ve parametreyi birlikte anahtar yapar. Anahtar eşleşmezse aynı ekran farklı bir ekran sayılır ve sökülüp yeniden kurulur.
- "Sekme ve yığın aynı geçiştir." Yığında yeni rota eklenir ve geri dönüş yolu oluşur. Sekmede rotalar kardeştir ve aralarındaki geçiş, yukarıdaki iki seçenekten hangisi kurulduysa onun akıbetini üretir.

## Özet

- Bu dersin akıbeti: korunan. Yeni rota itilince `/Stack/Screen[liste]` düğümü, özellikleri ve anahtarı değişmediği için korunan çıktı.
- Rota itmek yeni ekranın düğümlerini kurar, geri dönmek çıkarılan ekranın düğümlerini sökerek bu ekranın durumunu da yok eder.
- Sekme geçişi, görünmeyen sekmenin ağaçta kalıp kalmamasına göre güncellenen ya da sökülen ile kurulan üretir.
- Alttaki ekranın korunan olması, örtülmenin ağaca özellik olarak yazılmadığı varsayımına bağlıdır; yazılırsa aynı düğüm güncellenen olur.
- Kural gezinme kitaplığının iç tutumunu görmez; yalnız iki ağacı karşılaştırır.

## Sonraki Adım

Bu derste gezinme ekranların hangi düğümlerde kurulup söküldüğünü belirledi. Ekranlar arasında paylaşılan bilgi ise ayrı bir sorudur: bir sepet sayısı bir ekranda değişince başka bir ekrandaki rozet de değişmelidir. Sıradaki ders, `Durum Yönetimi`, tek bir değişikliğin hangi düğümü güncellediğini, hangisini korunan bıraktığını ölçer.
