Yönlendirme

Rota Tablosu

RouteItem alanları, iç içe rotalar, redirect ve alias, yol parametreleri, rota tablosunu sorgulama, tembel rotalar ve geliştirme kipindeki rota denetimi.

Rota tanımı (RouteItem)

Rotalar bir RouteItem[] dizisidir. Her öğe bir yolu (path) bir bileşene (control) eşler. Örnek tablo RouteItem'ın sık kullanılan alanlarını bir arada gösterir: desen kısıtlı ve adlandırılmış bir rota ({id(\d+)}, name), bir layout alias'ı, varsayılanlı opsiyonel parametre ve yönlendirme (Yönlendirmeye Giriş sayfasındaki tablonun genişletilmiş hâli):

import type { RouteItem } from "@motifx/core";
import MainLayout from "./layouts/MainLayout";
import NotesLayout from "./layouts/NotesLayout";
import NoteEmptyPage from "./pages/NoteEmptyPage";
import NotePage from "./pages/NotePage";
import type { Folder } from "./services/notes";

const folder = (name: Folder): RouteItem => ({
  path: `/${name}`,
  control: NotesLayout,
  meta: { folder: name },
  childs: [
    { path: "/", control: NoteEmptyPage },
    { path: "/{id(\\d+)}", name: `${name}-note`, control: NotePage },
  ],
});

export const routes: RouteItem[] = [
  {
    path: "/",
    control: MainLayout,
    childs: [
      { path: "/", redirect: "/notes" },
      { ...folder("notes"), alias: "/notlar" },
      folder("pinned"),
      folder("archive"),
      { path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") },
      { path: "/n/{id}", redirect: "/notes/{id}" },
    ],
  },
];
import MainLayout from "./layouts/MainLayout";
import NotesLayout from "./layouts/NotesLayout";
import NoteEmptyPage from "./pages/NoteEmptyPage";
import NotePage from "./pages/NotePage";

const folder = (name) => ({
  path: `/${name}`,
  control: NotesLayout,
  meta: { folder: name },
  childs: [
    { path: "/", control: NoteEmptyPage },
    { path: "/{id(\\d+)}", name: `${name}-note`, control: NotePage },
  ],
});

export const routes = [
  {
    path: "/",
    control: MainLayout,
    childs: [
      { path: "/", redirect: "/notes" },
      { ...folder("notes"), alias: "/notlar" },
      folder("pinned"),
      folder("archive"),
      { path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") },
      { path: "/n/{id}", redirect: "/notes/{id}" },
    ],
  },
];

Bu alanların etkisi:

RouteItem alanları

Alan Açıklama
path Rota yolu. Parametreler {name} biçiminde. Layout ve varsayılan çocuk için '/'; her çocuk yolu / ile başlar (geliştirme kipinde aksi MJX311 ile uyarılır). Aynı derinlikte statik segment parametreden önce gelir (/archive, /{slug}'ı yener).
control Rota bileşeni. Bileşen sınıfı, hazır bileşen örneği, () => Component, Options API fabrikası, () => import(...) (lazy) veya Promise olabilir. Yalnızca redirect tanımlı rotada zorunlu değildir. Hazır örnek (ya da örneğe çözülen Promise) verilen rota keepAlive gibi davranır: örnek bir kez kurulur, ayrılırken outlet'ten ayrılır, dönüşte aynı örnek geri bağlanır, parametre değişiminde yeniden kurulmaz (onUpdate çalışır); app.router.evict() bu örneği serbest bırakmaz, app.dispose() eder. Örnek serbest bırakılmışken rotaya girilirse sayfa kurulamaz: MJX304 raporlanır (nedeni MJX318) ve hata rotası gösterilir; her girişte taze durum isteyen sayfa sınıf ya da fabrika verir.
childs Alt rotalar. Tanımlıysa bu rota bir layout rotasıdır.
name Rotaya isimle erişim için (opsiyonel); href ve navigateByName bu adı kullanır.
meta Guard ve kancaların kullanabileceği serbest veri ({ requiresAuth: true, title: '...' }). Eşleşen zincirdeki (layout → çocuk) meta nesneleri birleştirilir; layout'a yazılan requiresAuth çocuklarında da görünür. Örnekte meta.folder layout rotasına yazılır, altındaki not rotasında da okunur.
extend Rotaya iliştirilen ekstra veri; meta gibi zincir boyunca birleştirilir. extend.targetOutlet rotanın bileşeninin yerleşeceği adlandırılmış RouterView'ı seçer (bkz. RouterView).
keepAlive true ise bileşen örneği korunur: ayrılırken outlet'ten ayrılır ve önbelleğe alınır (onDeactivated), geri dönüşte aynı örnek aynı konuma yeniden bağlanır (onActivated); ikisi de sayfanın görünür alt bileşenlerine iletilir. Önbellek app.router.evict(ad \| rota) (argümansız: hepsi; o an ekranda olan örnek atlanır) ya da app.dispose() ile boşaltılır.
redirect Bu rotaya gelindiğinde başka yola yönlendirir: {param} yer tutuculu yol dizesi ya da (to) => yol fonksiyonu. Ayrıntı: Yönlendirme ve alias.
alias Aynı rotaya açılan ek yol(lar); adres çubuğunda alias kalır. Ayrıntı: Yönlendirme ve alias.
validate(e) Eşleşme sırasında { uri, key, routes, params } ile çağrılır; false döndürürse bu rota eşleşmiş sayılmaz (başka bir rota ya da fallbacks.notFound devreye girer). Zincirdeki her rotanın validate'i çalışır. key rotanın adı, yoksa tam yolu (alias eşleşmesinde de kendi yolu); routes aynı kuralla anahtarlanmış rota tablosu (Map): routes.get(e.key) doğrulanan rotadır, başka bir rotaya adı ya da tam yoluyla ulaşılır.
onShow(component) Rotanın bileşeni kendi RouterView'ına her yerleştirildiğinde, bileşen örneğiyle çağrılır: ilk gösterim, parametre değişiminde yeniden oluşturma, keepAlive önbelleğinden dönüş, RouterView'ı yeniden kurulunca yeniden yerleşme. Layout rotaları için de çağrılır; gezinme boyunca yerinde kalan layout için tekrar çağrılmaz. Kancanın fırlattığı hata MJX306 koduyla raporlanır, gezinmeyi durdurmaz.

Gezinmeye bağlı rota kancaları (onEntering, onEnter, onLeave, onUpdate) Rota Kancaları ve Guard'lar sayfasında anlatılır.

Yönlendirme ve alias

Örnekteki /n/{id} dize biçiminde bir yönlendirmedir. Hedef bir hesaba bağlıysa fonksiyon verilir:

const shortcuts: RouteItem[] = [
  { path: "/n/{id}", redirect: "/notes/{id}" },
  { path: "/find/{q}", redirect: (to) => "/notes?q=" + encodeURIComponent(to.params.q) },
];
const shortcuts = [
  { path: "/n/{id}", redirect: "/notes/{id}" },
  { path: "/find/{q}", redirect: (to) => "/notes?q=" + encodeURIComponent(to.params.q) },
];

redirect

alias

Yol parametreleri

Parametreler {name} sözdizimiyle tanımlanır:

Sözdizimi Anlam
{id} Zorunlu parametre.
{id:1} Zorunlu; 1 yalnızca href / navigateByName yol üretirken değer verilmezse kullanılır (/h/{id:1} kalıbı /h adresiyle eşleşmez).
{id?} Opsiyonel.
{id?:5} Opsiyonel, varsayılan 5: adreste yoksa params.id '5' olur.
{id(\d+)} Desen kısıtı: segment yalnız parantez içindeki düzenli ifadeye uyarsa eşleşir (büyük/küçük harf duyarsız; desendeki yakalayan gruplar yok sayılır; ? ve : desenin parçasıdır). ? ve varsayılanla birleşir: {id(\d+)?:1}. Desen tek segmente uygulanır, içinde / olamaz. JavaScript dizesinde ters bölü iki kez yazılır: "/{id(\\d+)}".
{path+} Bir ya da daha çok segment: /files/a/b/c için params.path 'a/b/c' olur (düz metin; her segment ayrı çözülür, parçalar gerekirse split('/')). href için 'a/b' ya da ['a','b'] verilir, segmentler ayrı kodlanır. Desenle birleşir, desen her segmente uygulanır: {ids(\d+)+}.
{path*} {path+} gibi, ama hiç segment olmayabilir ({path?} gibi opsiyonel, :varsayılan alır).

Süslü parantez dışındaki : ve segmentin kalanı kalıptan düşer (/user/:id → /user/, hiçbir adresle eşleşmez); geliştirme kipinde denetim MJX319 ile uyarır.

Sıralamada {…+} ya da {…*} içeren rota, aynı derinlikte ve aynı statik sayısındaki rotalardan sonra gelir: /f/{a}/{b} /f/{rest+}'ten önce; /docs/{rest+} statik segmentiyle /{a}/{b}'den önce. Kullanılamayan desen (derlenmeyen, ( kapanmayan ya da / içeren) için denetim geliştirme kipinde MJX320 ile uyarır.

href, navigateByName ve redirect dizesi {…} yer tutucularını doldurur; değerler encodeURIComponent ile kodlanır (href('tag', { name: 'a/b' }) → /tags/a%2Fb, { name: 'çay' } → /tags/%C3%A7ay).

Parametrelere gezinme bağlamından/router'dan erişilir:

import { useNavigation } from "@motifx/core";
const nav = useNavigation();
const noteId = Number(nav.params.id);
import { useNavigation } from "@motifx/core";
const nav = useNavigation();
const noteId = Number(nav.params.id);

params sorgu dizesi değerlerini de içerir. Yol parametreleri gibi sorgu değerleri de dizedir ve yüzde kodlaması çözülmüş olarak gelir (/notes/5?tab=history → { id: '5', tab: 'history' }, /tags/%C3%A7ay?q=a%20b → { name: 'çay', q: 'a b' }); yolda + düz karakterdir, sorguda boşluktur; true, null, 2025-10-27 ya da {"a":1} gibi değerler de metin kalır. Sayı, boolean ya da tarih gerekiyorsa değeri kendiniz çevirin (Number(params.id)). Tekrarlanan anahtar (?tag=is&tag=ev) dizge dizisi olur (['is', 'ev']). Aynı adda yol parametresi sorgu değerini ezer. #… kısmı hiçbir zaman params'a girmez.

router.uri, onRouterChanged olayının uri'si, middleware ctx.uri'si ve guard'ın to.path'i adres biçimindedir: yüzde kodlu, adres çubuğuyla aynı (/tags/%C3%A7ay). Göstermek için decodeURIComponent, değer için params kullanın. navigate, RouterLink'in to'su ve onActive/onExact yolu ham (/tags/çay) ya da kodlu yazılabilir; ikisi aynı adrese gider ve aynı bağlantıyı etkin yapar.

Sorgu yalnızca gidilen adresten okunur: history modunda adreste ? yoksa params sorgu değeri içermez (önceki sayfanın sorgusu taşınmaz). hash/file modunda #'ten önceki sorgu (/?x=1#/a) sayfa düzeyindedir; kendi sorgusu olmayan her rotada params'a gelir, rotanın kendi sorgusu (#/b?z=3) varsa onun yerine o kullanılır.

Rota tablosunu sorgulama — resolve, href, routes

app.router gezinmeden rota tablosunu sorgulamak için üç üye taşır:

// Bir adres hangi rotaya eşleşir? (gezinmez, adres çubuğuna dokunmaz)
const { chain, result } = app.router.resolve("/notes/5");
if (result.ok) console.log(result.route?.name, result.params.id, result.meta.folder);  // "notes-note" "5" "notes"
chain;                                      // ['/', '/notes', '/5']
result.chain.map((r) => r.path);            // ['/', '/notes', '/{id(\\d+)}']: kökten rotaya tanımlar

// Tanım sırasıyla bütün rotalar (takma adlar hariç); menü ya da site haritası üretmek için
const paths = app.router.routes.map((r) => r.fullPath);
// Bir adres hangi rotaya eşleşir? (gezinmez, adres çubuğuna dokunmaz)
const { chain, result } = app.router.resolve("/notes/5");
if (result.ok) console.log(result.route?.name, result.params.id, result.meta.folder);  // "notes-note" "5" "notes"
chain;                                      // ['/', '/notes', '/5']
result.chain.map((r) => r.path);            // ['/', '/notes', '/{id(\\d+)}']: kökten rotaya tanımlar

// Tanım sırasıyla bütün rotalar (takma adlar hariç); menü ya da site haritası üretmek için
const paths = app.router.routes.map((r) => r.fullPath);

Adlandırılmış rotanın yolu href ile üretilir; RouterLink to, menü ve breadcrumb için. Örnekte bağlantının hedefi adlandırılmış rotadan üretilir (nav, useNavigation()'ın döndürdüğü router'dır):

<RouterLink to={nav.href(`${folder}-note`, { id: note.id })}>{note.title}</RouterLink>
const link = motifComponent(RouterLink, {
  to: nav.href(`${folder}-note`, { id: note.id }),
  childs: [motifComponent("text", (node: ComponentBase) => node.bindings.add("textContent", note, "title"))],
});
<RouterLink to={nav.href(`${folder}-note`, { id: note.id })}>{note.title}</RouterLink>
const link = motifComponent(RouterLink, {
  to: nav.href(`${folder}-note`, { id: note.id }),
  childs: [motifComponent("text", (node) => node.bindings.add("textContent", note, "title"))],
});
Üye Döndürür
resolve(uri) RouteResolution: { chain, result }. chain, app.router.chain ile aynı biçimdedir (string[], her rotanın parametreleri doldurulmuş kendi yolu). result, o adrese gidilince navigate'in döndürdüğü ResolveResult'tır: { ok, uri, fullPath, route, chain, params, meta, extend, aliasOf }; result.chain kökten rotaya kadar olan rota tanımlarıdır (RouteItem[]). Eşleşme yoksa result.ok false, chain []. Guard, middleware ve redirect çalışmaz.
href(ad, params?) Adlandırılmış rotanın parametreleri doldurulmuş yolu (navigateByName ile aynı hesap). 0 ve false değerleri yazılır; undefined, null ve '' verilen ya da hiç verilmeyen parametrede kalıbın varsayılanı kullanılır (varsayılan yoksa o segment yazılmaz). Kalıpta olmayan parametreler yazılmaz; sorgu gerekiyorsa üretilen yola eklenir (href("notes-note", { id: 3 }) + "?tab=history"). Ad yoksa MJX302 fırlatır.
routes RouteInfo[]: { fullPath, name, meta, route, chain }. Layout ve varsayılan çocuk ayrı öğelerdir; chain kökten bu rotaya kadar olan rota tanımlarıdır.

Lazy (tembel) yükleme

control alanında () => import(...) kullanmak, rota bileşenini yalnızca ihtiyaç anında yükler ve otomatik kod bölme (code splitting) sağlar. Bu biçimde verilen sayfa ayrı bir parçaya (chunk) ayrılır ve rotaya ilk gidildiğinde indirilir:

const settings: RouteItem = { path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") };
const settings = { path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") };

Yüklenen modül sayfayı default olarak dışa aktarmalıdır. Adlandırılmış dışa aktarım için eşleyin: control: () => import("./pages/SettingsPage").then((m) => m.SettingsPage). default dışa aktarımı olmayan modül ya da bileşen olmayan başka bir nesneyle sayfa kurulamaz: MJX304 raporlanır (nedeni MJX127) ve fallbacks.error gösterilir.

fallbacks.notFound ve fallbacks.error de aynı lazy biçimi destekler.

Rotanın import()'u yükleme görünümü ya da yeniden deneme kullanmaz. Bir sayfanın içindeki ağır parçayı tembel yüklemek, yüklenirken bir görünüm göstermek ve mobil ağda yeniden denemek için Lazy bileşeni kullanılır (bkz. Yeniden deneme).

Geliştirme kipinde rota denetimi

app.useDevelopment(true) useRouter'dan önce çağrıldığında rota tablosu kurulurken denetlenir; sorunlu tanım konsola uyarı olarak yazılır, router çalışmaya devam eder:

Kod Ne zaman
MJX310 Rota yolu boş (''); varsayılan çocuk için '/' yazılır.
MJX311 Çocuk rotanın yolu / ile başlamıyor ('notes').
MJX312 Çocuk rota ebeveyniyle aynı tam yola çıkıyor (varsayılan çocuk '/' hariç).
MJX313 Birden çok rota aynı tam yola çıkıyor.
MJX314 Çocuk rotanın alias'ı / ile başlamıyor.
MJX315 Alias rotanın kendi yoluna eşit.
MJX316 Birden çok rota aynı alias'ı kullanıyor.
MJX319 Yolda ya da alias'ta süslü parantez dışında : var (/user/:id).
MJX320 Parametre deseni kullanılamıyor: derlenmiyor, ( kapanmıyor ya da / içeriyor.

Sonraki adım

Rota bileşenlerinin ekranda nereye yerleştiğini öğrenmek için RouterView bölümüne geçin.