---
title: 'Bildirimler ve Derin Bağlantı'
source: 'https://academia.sh/tr/kurslar/react-native/bildirimler-ve-derin-baglanti'
course: 'React Native'
language: tr
updated: '2026-10-21T05:02:54+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Derin bağlantının rota listesine nasıl çevrildiğini açıklar'
    - 'Uygulama açıkken bağlantının yığına yalnız hedef ekranı kurduğunu ölçer'
    - 'Uygulama kapalıyken bağlantının ağacın tamamını kurduğunu ölçer'
    - 'Tanınmayan ve yinelenen bağlantının ağaçta komut doğurmadığını gösterir'
---

# Bildirimler ve Derin Bağlantı

Bildirime dokunmak ya da bir bağlantıyı açmak uygulamayı belirli bir ekranda başlatır. Ders açık uygulamada bağlantının yığına tek bir ekran kurduğunu, kapalı uygulamada ise ağacın tamamının kurulduğunu ölçer.

Önceki derslerde ağaçtaki değişiklik uygulamanın içinden geldi: bir dokunuş, bir yanıt, bir oturum. Bir değişiklik de dışarıdan gelir. Kullanıcı bildirime dokunur ya da bir bağlantıya tıklar; uygulama, sipariş 42'nin ekranında açılmak zorundadır. Bu ders dışarıdan gelen adresin rota listesine nasıl çevrildiğini ve uygulamanın açık ya da kapalı olmasının ağaçta ne fark ettiğini ele alır.

Kursun sorusu değişmez: **bu güncelleme görünüm ağacındaki düğüme ne yapıyor?** Akıbet korunan, güncellenen, kurulan ya da sökülendir; güncellenen, kurulan ve sökülen düğümlerin toplamı komuttur. Akıbeti elle atamayız, 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}`);
}
```

Model, bu akıbetin kuralını kurar; model çerçevenin kendisi değildir. Kural bağlantının nereden geldiğini görmez, yalnız önceki ve sonraki ağacı karşılaştırır.

## Bağlantı Rotaya Dönüşür

Derin bağlantı, uygulamanın belirli bir ekranını gösteren bir adrestir. Bildirim bu adresi taşır, bir e-postadaki bağlantı ya da bir başka uygulama onu açar. Bağlantı ekran değildir: adres bir metindir ve uygulamanın rota tablosu onu bir rotaya çevirir. Platform bağlantıyı iki yoldan iletir. Uygulama açıksa bağlantı çalışan uygulamaya bir olay olarak gelir. Uygulama kapalıysa bağlantı, uygulamayı başlatan ilk adres olarak alınır.

```swift
// Platform kodu: NotificationTap
func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {
    let link = response.notification.request.content.userInfo["link"] as? String
    pendingLink = link
    completionHandler()
}
```

Platform tarafı bağlantıyı yakalar ve JavaScript tarafına iletir. Çerçevede iki giriş vardır: açılışta ilk adresi sormak ve açıkken gelen olayı dinlemek.

```jsx
// Platform kodu: LinkListener
function useLink(onLink) {
  useEffect(() => {
    Linking.getInitialURL().then((url) => url && onLink(url));
    const sub = Linking.addEventListener("url", (e) => onLink(e.url));
    return () => sub.remove();
  }, []);
}
```

Bu iki parça ölçülmez; model platformu ve çerçeveyi çalıştırmaz.

**UK1.** Model bağlantıyı `siparis/<kimlik>` biçiminde tek bir adres olarak kurar. `openLink(routes, link)` mevcut rota listesini ve adresi alır, yeni rota listesini döndürür. Adres tanınmıyorsa ya da hedef rota zaten yığının tepesindeyse liste olduğu gibi döner.

```javascript
// link.mjs — derin baglantiyi rota listesine cevirir
export function openLink(routes, link) {
  const parts = link.split("/");
  if (parts[0] !== "siparis" || parts.length !== 2) return routes;
  const target = "siparis-" + parts[1];
  if (routes[routes.length - 1] === target) return routes;
  return [...routes, target];
}
```

**UK2.** Yığının ağacını birinci dersteki gibi rotalardan kurarız: `Stack` altında her rota için anahtarlı bir `Screen` ve içinde bir `Text`.

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

## Uygulama Açıkken

Kullanıcı sipariş listesinden bir siparişin ayrıntısına inmiş, sonra bildirim gelmiş. Yığında `liste` ve `detay` var. Bildirime dokunulunca uygulama zaten çalışıyor ve bağlantı olay olarak geliyor.

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

const routes = ["liste", "detay"];
const before = renderStack(routes);
const after = renderStack(openLink(routes, "siparis/42"));
const ops = reconcile(before, after);
printOps(ops);
countFates(ops);
```

```text
korunan: /Stack
korunan: /Stack/Screen[liste]
korunan: /Stack/Screen[liste]/Text
korunan: /Stack/Screen[detay]
korunan: /Stack/Screen[detay]/Text
kurulan: /Stack/Screen[siparis-42]
kurulan: /Stack/Screen[siparis-42]/Text
korunan: 5
guncellenen: 0
kurulan: 2
sokulen: 0
komut: 2
```

`/Stack/Screen[siparis-42]` kurulandır ve onunla birlikte altındaki `Text` kurulur. Yığındaki öteki ekranlar ve içlerindeki metinler korunandır. Kullanıcı geri dönerse kaldığı yeri bulur; bağlantı yığını sıfırlamadı, üstüne bir ekran koydu.

## Uygulama Kapalıyken

Uygulama kapalıyken bildirime dokunulursa bellekte ağaç yoktur. Platform uygulamayı başlatır ve ilk adres bağlantıdır. Başlangıç rotası `liste`, bağlantı hedefi `siparis-42`'dir; yığın ikisiyle birlikte kurulur.

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

const start = openLink(["liste"], "siparis/42");
const ops = reconcile(null, renderStack(start));
printOps(ops);
countFates(ops);
```

```text
kurulan: /Stack
kurulan: /Stack/Screen[liste]
kurulan: /Stack/Screen[liste]/Text
kurulan: /Stack/Screen[siparis-42]
kurulan: /Stack/Screen[siparis-42]/Text
korunan: 0
guncellenen: 0
kurulan: 5
sokulen: 0
komut: 5
```

Önceki ağaç olmadığı için ağacın tamamı kurulandır: yığın, iki ekran ve iki metin. Korunan düğüm yoktur, çünkü korunacak bir şey yoktur. Aynı bağlantı, uygulamanın açık ya da kapalı olmasına göre ağaçta iki ayrı iş yapar: açıkken tek bir ekran kurar, kapalıyken her şeyi. Bu iki ölçüm ayrı tutulmazsa bağlantının ağaca maliyeti yanlış anlaşılır.

## Platform Parçalarını Satır Satır Okumak

`NotificationTap` işlevi, kullanıcının bildirime dokunduğu anı yakalar. İşlev bildirimin içindeki bir alandan adresi okur ve bir değişkene yazar; ekrana hiçbir şey çizmez ve yığına hiçbir rota eklemez. Son satır, platforma işin bittiğini bildirir. Bu işlevin görevi yalnız adresi bırakmaktır: adresi rotaya çevirmek ve yığına yazmak uygulamanın sonraki adımıdır.

Bu bölünme önemlidir. Platform kodu bağlantının geldiğini bilir ama hangi ekranın açılacağını bilmez; o bilgi rota tablosundadır. Rota tablosu ise bağlantının nereden geldiğini bilmez. Bu yüzden iki parça birbirinden bağımsız değişebilir: bildirimin biçimi değişince platform kodu, ekran adları değişince rota tablosu güncellenir.

`LinkListener` parçası, adresin JavaScript tarafına iki yoldan ulaştığını gösterir. İlk çağrı, uygulama bağlantıyla başlatıldıysa o ilk adresi sorar; adres yoksa hiçbir şey olmaz. İkinci çağrı, uygulama çalışırken gelen adresleri dinler. Temizleme işlevi (`return () => sub.remove();`) dinleyiciyi kaldırır; böylece ekran ömrü bittiğinde dinleme de biter. İki girişin ikisi de aynı işleve, `onLink`'e bağlanır. Model bu ortaklığı `openLink` ile yansıtır: açık ve kapalı yollar aynı dönüşümü kullanır, yalnız elde önceden bir yığın olup olmaması farklıdır.

## Geri Dönmek

Bağlantıyla açılan ekranı kullanıcı kapatır. Yığından son rota çıkar ve bağlantının eklediği ekran ağaçtan gider. Bunu da ölçelim; çünkü bağlantı yığına bir ekran ekler ama bu ekranın ömrü bağlantıyla bitmez.

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

const ops = reconcile(
  renderStack(["liste", "detay", "siparis-42"]),
  renderStack(["liste", "detay"]),
);
printOps(ops.filter((op) => op.fate !== "korunan"));
countFates(ops);
```

```text
sokulen: /Stack/Screen[siparis-42]
sokulen: /Stack/Screen[siparis-42]/Text
korunan: 5
guncellenen: 0
kurulan: 0
sokulen: 2
komut: 2
```

Bağlantının kurduğu ekran ve içindeki metin sökülendir; geri kalan beş düğüm korunandır. Kuruluşun tersi olarak sökülme, kuruluşla aynı sayıda komut doğurur. Bağlantının ağaca maliyeti, ekranın yaşadığı süre boyunca bir kez ödenir ve ekran kapanınca bir kez daha: bir kurulum, bir söküm.

## İkinci Bağlantı

Kullanıcı bir siparişe gitmiş, geri dönmeden ikinci bir bildirime dokunmuş olabilir. Yığında `liste` ve `siparis-42` vardır, yeni bağlantı `siparis/43` adresini taşır.

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

const routes = ["liste", "siparis-42"];
const ops = reconcile(renderStack(routes), renderStack(openLink(routes, "siparis/43")));
printOps(ops.filter((op) => op.fate !== "korunan"));
countFates(ops);
```

```text
kurulan: /Stack/Screen[siparis-43]
kurulan: /Stack/Screen[siparis-43]/Text
korunan: 5
guncellenen: 0
kurulan: 2
sokulen: 0
komut: 2
```

İkinci bağlantı birincisini yerinden çıkarmadı; üstüne yeni bir ekran koydu. `siparis-42` korunandır, `siparis-43` kurulandır. Model bu seçimi `UK1` ile yaptı: adres tanınıyorsa ve hedef tepede değilse rota eklenir. Gerçek bir uygulama bu durumda eski siparişi değiştirmeyi seçebilirdi; o hâlde ölçüm farklı bir akıbet verirdi ve bu ders o seçimi ölçmez. Ölçülen, modelin kurduğu davranıştır.

## Rota Tablosu Ne Yapar

Rota tablosu, adresleri rota adlarına bağlayan küçük bir kural kümesidir. Modelimizde bu kural tek satırdır: `siparis/<kimlik>` biçimindeki adres `siparis-<kimlik>` rotasına dönüşür. Gerçek bir uygulamada tablo daha uzundur ve her satır bir ekranı, bazen de o ekranın parametrelerini tanımlar. Tablonun iki sınırı vardır. Tanımadığı adres için bir şey üretmez, ki bu ders bunu aşağıdaki `taninmayan` ölçümüyle gösterecek. Tanıdığı adres için ise yalnız rota adını üretir; ekranın içeriği, yani siparişin kendisi, ekran açıldıktan sonra ağ katmanından gelir.

Bu ikinci sınır ağaç açısından önemlidir. Bağlantı ekranı kurar, ama siparişin ayrıntıları henüz yoktur. Ekran önce yükleniyor hâlinde açılır, sonra veri gelince güncellenir. Bağlantının ağaca maliyeti bu yüzden iki aşamalıdır: ekranın kurulması ve içeriğin gelmesi. Bu derste yalnız ilk aşama ölçüldü; ikinci aşama Ağ ve Veri dersinin konusudur.

## Başlangıç Sırası

Uygulama bağlantıyla başlatıldığında iki yol vardır. Birincisinde uygulama ilk adresi sorar ve ağacı doğrudan bağlantının gösterdiği yığınla kurar; ölçümümüz bu yolu gösterdi ve beş düğümün beşi kurulan oldu. İkincisinde uygulama önce başlangıç ekranını kurar, adresi sonra öğrenir ve bağlantıyı açık uygulamaya gelen bir olay gibi işler. Bu yolda başlangıç yığınının üç düğümü (`Stack`, `liste` ekranı ve metni) önce kurulur, bağlantının iki düğümü sonra eklenir; toplam yine beş kurulan düğümdür, ama kullanıcı kısa bir an için yalnız başlangıç ekranını görür.

İki yol komut sayısı bakımından eşittir. Aralarındaki fark ağacın değil, kullanıcının gördüğü ara durumun farkıdır. Kural ara durumu görmez; yalnız karşılaştırılan iki ağacı görür. Bu yüzden bu iki yolun karşılaştırılması ağaç akıbetinin dışında, bir tasarım değerlendirmesidir.

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

Bağlantının uygulamaya ulaşması ağacın değişmesi demek değildir. Rota tablosu adresi tanımayabilir, ya da bildirim iki kez gelebilir. İki durumda da bağlantı işlenmiştir ama ağaç değişmez.

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

function measure(label, routes, link) {
  console.log(label);
  countFates(reconcile(renderStack(routes), renderStack(openLink(routes, link))));
}

measure("taninmayan:", ["liste", "detay"], "kampanya/7");
measure("yinelenen:", ["liste", "siparis-42"], "siparis/42");
```

```text
taninmayan:
korunan: 5
guncellenen: 0
kurulan: 0
sokulen: 0
komut: 0
yinelenen:
korunan: 5
guncellenen: 0
kurulan: 0
sokulen: 0
komut: 0
```

İki ölçümde de komut 0'dır: tüm düğümler korunandır. Akıbet bağlantının işlenip işlenmediğini ölçmez; ağacın ne olduğunu ölçer. Bildirime dokunulmuş, uygulama bağlantıyı almış ve rota tablosu karar vermiş olabilir; ağaçta hiçbir iz kalmayabilir.

## Yaygın Yanılgılar

- "Bağlantı geldi, demek ki yeni ekran açıldı." Ekran, rota listesine bir rota eklenirse açılır. Tanınmayan ya da yinelenen bağlantı listeyi değiştirmez.
- "Bildirim uygulamayı hep sıfırdan başlatır." Uygulama açıksa bağlantı olay olarak gelir ve yığın korunur; sıfırdan kurulum yalnız uygulama kapalıyken olur.
- "Bildirimin kendisi ağaçta görünür." Bildirim işletim sisteminin bildirim alanında durur; ağaca yalnız ona dokunulunca gelen bağlantı girer.
- "Aynı bildirim iki kez gelirse iki ekran açılır." Hedef rota zaten tepedeyse model listeyi değiştirmez. Yinelenen bağlantı ölçümü komut 0 verdi.
- "Tanınmayan bağlantı hata verir." Model tanınmayan adreste listeyi olduğu gibi döndürür ve ağaç değişmez. Kullanıcıya bir şey söylemek isteniyorsa bu ayrı bir düğüm olarak ağaca yazılmalıdır; o zaman ölçüm komut 0 yerine bir kurulan düğüm gösterirdi.
- "Bağlantı yığını her zaman büyütür." Bağlantı yığına bir rota ekleyebilir, hiçbir şey eklemeyebilir ya da bir uygulama yığını baştan kurmayı seçebilir. Bu ders yalnız ekleme davranışını ölçtü.
- "Bildirim izni bağlantıyı ağaçta gösterir." İzin bildirimin gösterilip gösterilmeyeceğini belirler. Gösterilen bildirime dokunulmadıkça uygulamaya bağlantı ulaşmaz ve ağaç değişmez.
- "Aynı bağlantı her zaman aynı ağacı verir." Sonuç, bağlantının geldiği andaki yığına bağlıdır. Aynı `siparis/42` adresi uygulama kapalıyken, önceki ağaç yokken beş, `liste` ve `detay` ekranlı yığında iki kurulan düğüm üretti. Bağlantının maliyetini yalnız adrese bakarak söylemek mümkün değildir.

## Özet

- Bu dersin akıbeti: kurulan. Uygulama açıkken bağlantı `/Stack/Screen[siparis-42]` ekranını kurar, alttaki ekranlar korunandır.
- Uygulama kapalıyken önceki ağaç yoktur; bağlantı ağacın tamamını kurulan yapar.
- Aynı bağlantı açıkken tek bir ekran, kapalıyken tüm ağaç kurar; iki durum ayrı ölçülür.
- Tanınmayan ve yinelenen bağlantı ağaçta komut doğurmaz, bağlantının işlenmiş olması ağacın değiştiği anlamına gelmez.
- Bağlantıyı adres olarak taşıyan platform koduyla onu rotaya çeviren rota tablosu ayrı iki iştir; akıbeti ikincisinin sonucu belirler.

## Sonraki Adım

Bu derse kadar ağaç kesikli adımlarla değişti: bir dokunuş, bir yanıt, bir bağlantı. Parmak ekranda sürüklenirken değişiklik her karede olur. Son ders, `Hareketler ve Animasyonlar`, aynı hareketin ağaca iki yoldan yazılması hâlinde komutun nasıl ayrıştığını ölçer.
