Merhaba. Bu sayfada https://reactnavigation.org/ sitesinde yayınlanan React Navigation 5.x versiyonunun dokümantasyonunun başlangıç kısmını lisanım yettiğince Türkçeleştireceğim. Bu sayfayı okurken şunları bilmelisiniz:
Navigation kelimesini Türkçeye gezgin olarak çevrimek istemedim. Navigation veya navigator kelimeleri sayfalar arasında gezmek, sayfayı yönlendirmek... cümle içine nasıl denk geliyorsa öyle anlamlara geliyor ve sanırım gezgin deyince konsepti anlamak zorlaşıyor.
Component kelimesini de bileşen olarak çevirmeyi düşünmüyorum. React Native kullanıyorsak bu kelimeye bu şekilde aşinayızdır. Aynı şekilde state kelimesini de durum diye çevirmeyeceğim. Ben yine de bir kelimenin hangi anlamlarda kullanıldığını daha anlaşılır kılmak için anlamları/manaları bu şekilde / ile ayırarak gösterdim.
Benim yazının arasına girip kendimce eklediğim yazılar olursa bunları bu renkte belirteceğim.
İsterseniz asıl dokümantasyonu da burayla eş zamanlı takip edebilesiniz diye sayfayı CSS ile az-çok aslına benzettim. Ama dayanamayıp kendi yorumumu kattığım stillendirmeler de yok değil. :)
Burada anlatılan bilgilerle tipik, küçük bir mobil uygulama yapmanıza yetecek bilgiler edinecek ve daha derine inmek için temel atmış olacaksınız.
Eğer zaten Javascript'i biliyorsanız React Navigation kullanmaya hızlıca başlayabilirsiniz ama bilmiyorsanız önce orada kendinizi geliştirmelisiniz.
Javascript'te sıkıntınız yoksa burada size yardımcı olacak bazı kaynaklar var:
React Native için gerekli paketleri kurun:
npm ile kurulum için:
npm install @react-navigation/native
yarn ile kurulum için:
yarn add @react-navigation/native
React Navigation bazı temel araçlardan oluşur. Bu araçlar, navigator yapısını kurmak için kullanılır. Merak etmeyin, ileride neden bahsettiğimizi anlayacaksınız. Biz şimdilik sonradan uğraşmamak temel bağımlılıkların kurulum işini halledelim ve hızlıca kod yazmaya geçelim.
Şimdi kuracağımız kütüphaneler react-native-gesture-handler, react-native-reanimated, react-native-screens, react-native-safe-area-context ve @react-native-community/masked-view. React Navigation, çalışmak için bu kütüphanelere bağımlı. Sizde bu kütüphanelerin son sürümleri zaten kuruluysa yeniden kurmanıza gerek yok tabii ki.
Projenizin kök klasörüne gidin ve şu komutu verin:
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
Böylece Merhaba React Navigation başlığına geçebilirsiniz.
Projenizin kök klasörüne gidin ve şu komutu verin:
npm ile kurulum için:
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
yarn ile kurulum için:
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
Not: Kurulumdan sonra eş bağımlılıklarla ilgili uyarılar alabilirsiniz. Bunlar genelde bazı paketlerde belirtilen yanlış versiyon aralıklarından kaynaklanır. Uygulamanız oluşturulabiliyorsa bu uyarıları göz ardı edebilirsiniz.
Not: Eğer projenizde react-native-windows kullanıyorsanız react-native-gesture-handler da kullanın.
React Native 0.60 ve üzeri sürümler için linkleme işlemi otomatik yapılır. Yani sizin run react-native link yazmanıza gerek yok.
Eğer Mac'te çalışıyor ve iOS için geliştirme yapıyorsanız linkleme yapmak için pods'u (Cocoapods) kurmanız gerekiyor.
npx pod-install ios
react-native-gesture-handler
kurulumunu tamamlamak için index.js veya App.js gibi uygulamanızın giriş dosyasının en üst satırına (bu satırdan önce başka bir satır olmadığına dikkat edin) ekleyin:
import 'react-native-gesture-handler';
Not: Eğer Android veya iOS için geliştirme yapıyorsanız bu adımı atlamayın. Geliştirme sırasında düzgün çalışsa bile yayınlama aşamasında uygulamanız çökebilir. Diğer platformlar için bu adımı atlayabilirsiniz.
Şimdi tüm uygulamayı NavigationContainer ile sarmamız gerekiyor. Genellikle giriş dosyanız olan index.js veya App.js içinde bunu yaparız.
import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
export default function App() {
return (
<NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
);
}
Not: Bir navigator kullandığınızda (stack navigator gibi) onun bağımlılıklarını eklemek için kurulum yönergelerini de uygulamanız gerekir. Eğer "Unable to resolve module" diye bir hata alıyorsanız, bu modülü projenize kurmanız gerekiyor demektir.
Artık uygulamanızı cihaz/simülatör üzerinde build etmeye hazırsınız.
Bir web tarayıcıda, başka bir sayfaya gitmek için <a>
tag'ını kullanırsınız. Kullanıcı link'e tıkladığında URL, tarayıcının history stack'ine (geçmiş yığınına) eklenir. Kullanıcı geri butonuna bastığında tarayıcı, yığına son eklenen (yığının en üstündeki) URL'i yığından alıp gösterir ve böylece aktif sayfa önceki sayfa olur. React Native, yerleşik olarak, tarayıcılardaki gibi bir history stack'e sahip değil. İşte bu noktada da React Navigation devreye giriyor.
React Navigation'un Stack Navigator sağlayıcısı (stack navigator provider) ekranlar arasında geçişi ve navigation geçmişi yönetimini yapmanın bir yoludur. Eğer sizin uygulamanız tek bir yığın/stack navigator'e sahipse uygulamanız web sayfası gibi çalışır. Kullanıcılar sayfa değiştirmeye kalktıklarında yığına/stack'a sayfalar eklenir/çıkarılır ve kullanıcıya yığının üstündeki ekran sunulur. Bunun bir web tarayıcıyla arasındaki fark, sayfa geçişleri animasyonlarıdır. Yığın sağlayıcı, Android ve iOS kullanıcılarının kendi sistemlerinde alışık oldukları sayfa geçişini (iOS için yatay, Android için dikey sayfa geçişleri gibi) sağlamış olur.
Birazdan en yaygın kullanılan navigation aracı olan yığın/stack navigator'u oluşturmakla işe başlayacağız: createStackNavigator
Yığın kelimesi burada anlatılanı güzel anlatıyor. Üst üste duran kartlar gibi düşünün. Siz AnaSayfa adlı sayfadasınız. Sistem, masanın üstündeki yığın alanına üzerinde Anasayfa yazılı bir kart koyuyor. Hakkımızda sayfasına geçtiğinizde AnaSayfa yazılı bir kartın üzerine Hakkımızda kartını konuyor. İletişim sayfasına geçtiğinizde de Hakkımızda kartının üstüne İletişim yazılı kart konuyor. Artık yığında 3 tane kart/sayfa var. Geri butonuna basıyorsunuz ve sistem en üstteki kartı kaldırıp atıyor ve şimdi en üstte Hakkımızda sayfası olduğu için onu görüyorsunuz. Bu sefer de Ürünler sayfasına gittiniz. Sistem, Hakkımızda kartının üstüne Ürünler kartını koyuyor. Ürünler sayfasındayken İletişim sayfasına geçtiğinizde de Ürünler kartının üstüne İletişim kartı konuyor. Şimdi yığında sırasıyla Anasayfa>Hakkımızda>Ürünler>İletişim kartları/sayfaları var ve en üstte İletişim kartı olduğu için onu görüyoruz. Peki Hakkımızda sayfasına gitmek istediğimizde ne oluyor? Sistem yığını kontrol ediyor. Hakkımızda sayfası yığında var mı? Var. O zaman sistem, Hakkımızda sayfası en üstte kalana kadar yığının üstündeki kartları atıyor. Şimdi yığında Anasayfa>Hakkımızda var. Yani geri butonuna basarsak Hakkımızda kartı da atılır ve AnaSayfa'ya döneriz. Yığınımız "son giren ilk çıkar" mantığıyla çalışıyor.
React Navigation'da sayfalar arası gezinme işini sağlayan her aracın kendi kütüphanesi vardır. Stack navigator (yığın navigator'u) kullanmak istiyorsak şu kütüphaneyi kurmamız gerekir: @react-navigation/stack:
npm ile kurulum için:
npm install @react-navigation/stack
yarn ile kurulum için:
yarn add @react-navigation/stack
💡 @react-navigation/stack çalışmak için @react-native-community/masked-view ve kurulum aşamasındaki diğer kütüphanelere bağımlıdır. Eğer bu kurulumları henüz yapmadıysanız geri dönüp bu kurulumları nasıl yapacağınızı okuyun.
createStackNavigator
, şu 2 property'i barındıran bir obje döndüren bir fonksiyondur: Screen ve Navigator. Bunların ikisi de navigation ayarların yapmak için kullanacağınız React component'leridir. Yakında göreceğiniz üzere Navigator
, yönlendirme ayarlarını içeren Screen
component'leri barındırmalıdır.
NavigationContainer
, navigation ağacımızı yöneten ve navigation state'ini tutan bir component'tir. Bu component, tüm navigation yapısını sarmalıdır. Genellikle bu komponent bütün uygulamanızı sararak, App.js'ten (veya sizin uygulamanızın giriş dosyası neyse neyse) render edilmesi için export edilir.
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Bu örneği Snack üzerinde deneyin
Kodu çalıştırırsanız üstteki görsel gibi bir sayfa göreceksiniz. Navigation barında ve içerikte gördüğünüz stil, stack navigator için varsayılan ayarlara göre verildi. Bunları nasıl değiştirebileceğimizi ileride göreceğiz.
name="Home" yazan yerdeki Home değerini, yani yönlendirme adını ne verdiğiniz önemli değildir. "Home", "home", "HOME", "AnaSayfa" gibi istediğiniz değeri verebilirsiniz. Biz ilk harfi büyük şekilde yönlendirme adı vermenizi öneririz. Bu, "şu sayfaya git" derken belirteceğiniz addır.
Bir Screen component'i için name ve component property'leri zorunludur. Kullanabileceğiniz diğer ayarlar için stack navigator reference sayfasını inceleyebilirsiniz.
Tüm yönlendirme/routing ayarları, Navigator'umuzda varsayılan olarak verilmiştir. Biz Navigator'umuza varsayılan bir sayfa/ekran/rota atamadık. Bu yüzden varsayılan ayarlarla HomeScreen
sayfasını görüyorsunuz.
Stack/yığın navigator'umuzda bir sayfa/ekran/rota daha ekleyelim ve HomeScreen
ekranımızı da ilk açılış ekranı olacak şekilde ayarlayalım.
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Artık navigator'umuzun iki ekranı var: bir Home
ekranı ve bir de Details
ekranı. Screen component'i, gezinmek için kullanacağımız sayfa/ekran/rota adına karşılık gelen bir name
prop'u ve render edeceği component'i belirten bir component
prop'u alır.
Bu kodda ilk açılış ekranı, Home
adıyla ifade ettiğimiz HomeScreen
component'idir. Details
yolu da DetailsScreen
component'ine karşılık gelir. Stack için ilk yol (yığının en üstündeki yol) Home
yoludur. Bunu değiştirip kaydedin ve uygulamayı reload edin (çünkü React Native'in Fast Refresh'i initialRouteName
'deki değişikliği güncellemeyecektir) ve ilk ekran olarak Details
ekranının geldiğini cihazınızda/simülatörünüzde görün. Sonra Home
ekranına geri dönün ve yine reload edin.
Not:component
prop'u component değeri alır. Değer olarak fonksiyon vermeyin (Örn:component={()=><DetailsScreen />}
). Aksi taktirde component'iniz üst component yeniden oluşturulduğunda tüm state'ini kaybederek bağlantısını kesip yeniden bağlanacaktır.
Navigator'un her bir screen'inde/ekranında bazı özelleştirmeler yapılabilir. Mesela ekranın header kısmında oluşan başlık... Bu seçenekler, her bir Screen
component'i için options
parametresiyle verilebilir.
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Overview' }} />
Bazen bir sayfaya/ekrana ek parametreler aktarmamız gerekebilir. Bunu 2 yolla yapmamız mümkün:
Screen
için bir component
prop'u belirtmek yerine ekran için bir render callback kullanın:
<Stack.Screen name="Home">
{props => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
Varsayılan olarak React Navigation, gereksiz işlemeleri önlemek için, screen bileşenine optimizasyonlar uygular. Ama siz render callback yöntemini kullanırsanız bu optimizasyonlar ortadan kalkar. Dolayısıyla, bir render callback kullanıyorsanız, performans sorunlarını önlemek için screen component'iniz içinReact.memo
veyaReact.PureComponent
kullandığınızdan emin olmanız gerekir.
Doğal olarak akıllardaki soru: "Home
ekranından Details
ekranına nasıl yönlendirme yapacağım?". Sonraki konu bunu içeriyor.
Önceki bölüm Merhaba React Navigation ile iki rotalı/sayfalı/ekranlı stack navigator yaptık (Home
ve Details
), ama kullanıcının Home
ekranından Details
ekranına nasıl geçeceğini öğrenmedik.
Eğer bu işi bir web tarayıcıda yapmaya kalksaydık şu şekilde bir kodu rahatça html'e verebilirdik:
<a href="details.html">Go to Details</a>
Diğer bir yol da şu olabilirdi:
<a onClick={() => { window.location.href='details.html' }}>Go to Details</a>
Biz ikincisine benzer bi'şey yapacağız. Ama window.location
yerine ekran/sayfa component'lerimize aktarılan (component'ten prop olarak alabileceğimiz) navigation
prop'unu kullanacağız.
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen( {navigation} ) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button title="Go to Details" onPress={()=>navigation.navigate('Details')}
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Eklediğimiz kodları parça parça inceleyelim:
navigation
- Stack navigator kullanımında navigation
prop'u her screen componentine (tanım) gönderiliyor.navigate('Details')
- Kullanıcıyı göndermek istediğimiz rota adı ile navigate
fonksiyonunu çağırıyoruz.Navigator'umuzta tanımlamadığımız bir rota adını navigation.navigate()
fonksiyonuna verirsek; geliştirme aşamasındayken bir hata yazdırır, yayınlama aşamasındayken hiçbir şey olmaz. Yani sadece navigator'umuzda tanımlanmış rotalara gidebiliriz. Rastgele bir component'e gidemeyiz.
Şimdi iki rotaya/ekrana/sayfaya sahip bir stack'ımız/yığınımız var. Peki Details
rotasından/ekranından yine Details
rotasına/ekranına gidersek ne olur?
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button title="Go to Details" onPress={()=>navigation.navigate('Details')}
</View>
);
}
function DetailsScreen( {navigation} ) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button title="Go to Details... again" onPress={()=>navigation.navigate('Details')}
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Bu kodu çalıştırıp "Go to Details... again" butonuna dokunursanız hiçbir şey yapmadığını fark edeceksiniz! Çünkü zaten Details
ekranındayız. navigate()
fonksiyonuna bir rota verdiğimizde kabaca ona "bu sayfaya git" deriz. Ama zaten o sayfadaysak hiçbir şey yapmaz.
E hadi başka bir Details
ekranı eklemek istediğinizi varsayalım. Bu, bir ekrana benzersiz veriler aktardığınız durumlarda oldukça yaygındır (ileride params
konusuna geleceğiz!). Bunu yapmak için navigate()
fonksiyonu yerine push()
fonksiyonuyla değiştirin. Bu, mevcut ekran geçmişinizden bağımsız olarak başka bir ekran eklemek istediğimizi belirtir. Aynı sayfanın yığının üstüne tekrar atıldığını, üst üste bindiğini düşünebiliriz.
<Button title="Go to Details... again" onPress={() => navigation.push('Details')} />
Bu örneği Snack üzerinde deneyin
push()
fonksiyonunu her çağırdığımızda navigation yığınına/stack'ına yeni bir rota/ekran ekleriz. navigate()
fonksiyonunu çağırdığımızdaysa önce mevcut rotayı bulmaya çalışır ve yalnızca, eğer yığında/stack'ta henüz bir tane yoksa, yeni rotayı yığına ekler.
Stack navigator tarafından otomatik sağlanan header, o an açık olan ekrandan geri dönmek mümkün olduğunda otomatik olarak geri dönmeye yarayan bir buton içerir (O anda yığında sadece 1 tane ekran/rota/sayfa varsa geri dönülecek bir ekran/rota/sayfa olmadığından geri düğmesi de yoktur).
Bazen bu davranışı otomatik atanan geri butonuyla değil de programatik olarak tetiklemek isteyebilirsiniz. Bunun için, navigate()
ve push()
fonksiyonlarınızı kullandığınız aynı yöntemle navigation.goBack()
fonksiyonunu kullanabilirsiniz. DetailsScreen
component'ine bir buton daha ekleyip bunu test edebilirsiniz:
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button title="Go to Details" onPress={()=>navigation.navigate('Details')}
</View>
);
}
function DetailsScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button title="Go to Details... again" onPress={()=>navigation.push('Details')}
<Button title="Go to Home" onPress={()=>navigation.navigate('Home')}
<Button title="Go back" onPress={()=>navigation.goBack()}
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Android'de React Navigation, donanımın sağladığı geri düğmesine bağlanıp kullanıcı bu düğmeye bastığında goBack()
fonksiyonunu çalıştırır. Böylece donanımın geri butonu da kullanıcının beklediği gibi davranmış olur.
Bazen de yığının derinliklerindeyken ana ekrana dönmek ve yığındaki diğer sayfaları yok saymak isteyebilirsiniz. Bu durumda, Home
ekranına geri dönmek istediğinizde pekala navigation.navigate('Home')
özelliğini kullanabilirsiniz (push
kullanmayın. navigate
kullanın ve farkı görün). Buna alternatif olarak navigation.popToTop()
kullanabilirsiniz. Bu da sizi yığındaki ilk sayfaya döndürür.
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button title="Go to Details" onPress={()=>navigation.navigate('Details')}
</View>
);
}
function DetailsScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button title="Go to Details... again" onPress={()=>navigation.push('Details')}
<Button title="Go to Home" onPress={()=>navigation.navigate('Home')}
<Button title="Go back" onPress={()=>navigation.goBack()}
<Button title="Go back to first screen in stack" onPress={()=>navigation.popToTop()}
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Daha önce parametreler hakkında daha detaylı bilgi vereceğiz demiştik. Pekala, şimdi zamanı geldi!
Artık bir stack navigator'unu nasıl oluşturacağımızı ve bununla ekranlar arasında nasıl geçiş yapabileceğimizi bildiğimize göre, ekranlar arasında geçerken nasıl veri aktarabileceğimize bakalım.
Veri aktarımını iki taraflı (veriyi gönderen ve alan) olarak ele alırsak
navigation.navigate()
fonksiyonunun 2.parametresi olarak verileri gönderebiliriz.
navigation.navigate('Details', { /* parametreler buradan gönderilebilir */ })
route.params
ile parametreleri alabiliriz.Geçtiğiniz parametrelerin JSON.stringify()
edilebilir öneriyoruz.
HomeScreen
component'imizden/sayfamızdan/ekranımızdan veri gönderip DetailsScreen
içinde yakalayalım.
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button title="Go to Details" onPress={()=>navigation.navigate('Details',
{
itemId: 86,
otherParam: 'ne istersek...'
}
)}
</View>
);
}
function DetailsScreen( { route, navigation } ) {
const { itemId, otherParam } = route.params;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>ItemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button title="Go to Details... again" onPress={()=>navigation.push('Details',
{
itemId: Math.floor(Math.random() * 100),
}
)}
<Button title="Go to Home" onPress={()=>navigation.navigate('Home')}
<Button title="Go back" onPress={()=>navigation.goBack()}
<Button title="Go back to first screen in stack" onPress={()=>navigation.popToTop()}
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Ekranlar/screen'ler/sayfa component'leri, tıpkı state'lerini güncelledikleri gibi, parametrelerini de güncelleyebilirler. navigation.setParams()
fonksiyonu, bir ekranın parametrelerini güncellemenizi sağlar. Daha fazla ayrıntı için API reference for setParams
bölümünü inceleyin.
Basit kullanım:
navigation.setParams( { query: 'someText', } )
Not:setParams
fonksiyonunu,options
ile ayarlanan başlık vb. gibi ekran özelliklerini güncellemek için kullanmaktan kaçının. Bunları güncelleyeceksenizsetOptions()
kullanın.
Ekrana başlangıç değerleri olan parametreler gönderebilirsiniz. Siz ekrana giderken herhangi bir parametre belirtmezseniz bu parametreler bu ilk değerleriyle sayfada kullanılabilecektir. Daha önce sayfaya gönderdiğimiz parametreleri nasıl okuyorduysak bunları da aynı şekilde okuyabiliriz. Bunu sağlayan, Screen
component'inin initialParams
prop'udur.
<Stack.Screen name="Details" component={DetailsScreen} initialParams={{ itemId: 42 }} />
Parametreleri sadece yeni ekrana geçerken mi verebiliyoruz, diye düşünebilirsiniz. Aslında önceki ekrana geçerken de parametre göndermemiz gerekebilir. Mesela "Create Post"/"Gönderi Oluştur" butonu olan bir ekranınız olsun ve bu butona basıldığında yeni bir ekran açılsın. Gönderi oluşturulduktan önceki ekrana geri dönelim ve gönderi verilerini de önceki ekrana taşıyalım.
Şimdi siz burada navigation.goBack()
fonksiyonuna parametre ekleyeceğiz sanıyorsunuz ama öyle değil. Yine navigation.navigate()
fonksiyonunu kullanacaksınız ve route olarak önceki sayfanın adını verip parametre göndereceksiniz. Aslında yukarıda yaptığımız sayfaya geçerken parametre göndermekle aynı işlemi yapıyoruz. Aşağıdaki örnekte CreatePostScreen
component'ine gidiliyor ve metin kutusuna girilen veri, butona basılınca HomeScreen
component'ine aktarılıyor. Ayrıca, (dokümantasyondan farklı olarak) tüm sayfanın kodlarını verip yapılacak değişiklikleri işaretleyeceğim. Aynı örnek üzerinde ilerlersek daha iyi anlaşılır sanırım.
// Yeni bir uygulama oluşturduğunuzda kök klasörde gelen App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen({ navigation , route }) {
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
}
}, [route.params?.post]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button title="Go to Details" onPress={()=>navigation.navigate('Details')}
<Button title="Create Post" onPress={()=>navigation.navigate('CreatePost')}
</View>
);
}
function CreatePostScreen({navigation, route}) {
const [postText, setPostText] = React.useState('');
return (
<>
<TextInput
multiline
placeholder="What's on your mind?"
style={{ height: 200, padding: 10, backgroundColor: 'white' }}
value={postText}
onChangeText={setPostText}
/>
<Button title="Done" onPress={ ()=> navigation.navigate('Home', { post: postText }) } />
</>
);
}
function DetailsScreen({navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button title="Go to Details... again" onPress={()=>navigation.push('Details')}
<Button title="Go to Home" onPress={()=>navigation.navigate('Home')}
<Button title="Go back" onPress={()=>navigation.goBack()}
<Button title="Go back to first screen in stack" onPress={()=>navigation.popToTop()}
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="CreatePost" component={CreatePostScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Bu örneği Snack üzerinde deneyin
Burada "Done" butonuna basıldığıktan sonra Home
ekranındaki route.params
, navigate
ile gönderdiğinzi post'u ekrana yansıtacak şekilde güncellenmiş olacak.
Eğer nested navigator'unuz varsa ona da birazcık farklı bir şekilde parametre gönderebilirsiniz. Örneğin Account
ekranınız var ve buna parametre göndermek istiyorsunuz. Parametreleri aşağıdaki gibi geçebilirsiniz:
navigation.navigate('Account', {
screen: 'Settings',
params: { user: 'Jane' }
});
Nesting navigator'ler hakkında daha fazla bilgi için o konuya göz atın.
Burada aslında mesela stack navigator içinde stack navigator veya bottom tab navigator gibi başka navigatorler kullanmakla ilgili bi'şeyler bilmeniz gerekiyordu ama dokümantasyon bu örneği önden vermek istemiş. Yani henüz bu işlemi dokümantasyonda görmediğimiz için bu başlıkta ne anlatıldığını anlamamış olmanız doğal.
Parametrelerde nasıl veri gönderdiğimizi anlamak önemli. Parametreler, bir Screen
'e verilmiş options
prop'u gibidirler. Yalnızca ekranda görünecekleri yapılandırmak için bilgi içermelidirler. Ekranda görüntülenecek tüm verileri iletmekten kaçının (mesela kullanıcı bilgilerini toptan atmak yerine bir userId gönderin). Ayrıca birden çok ekran tarafından kullanılan verileri iletmekten de kaçının çünkü bu tip veriler global olarak tutulmalıdır.
Rota nesnesini bir URL gibi de düşünebilirsiniz. Bir URL'den sayfaya veri iletmek istediğinizde ne tür veriler gönderirsiniz? Mesela bir kullanıcının profil sayfasını göstermek istiyorsanız kullanıcının adını, yaşını, fotoğrafını vb. tüm verilerini iletmezsiniz. Sadece kullanıcının id'sini gönderirsiniz ve diğer verileri bu id yardımıyla elde edersiniz. Bu şekilde, bir URL'de olmaması gerektiğini düşündüğünüz verileri route
parametrelerinde de göndermeyin. Yani sayfalara mümkün olduğunca az veri göndermeniz doğru bir yaklaşım olacaktır.
// Bunu yapmayın
navigation.navigate('Profile', {
user: {
id: 'jane',
firstName: 'Jane',
lastName: 'Done',
age: 25,
},
});
Bu şekilde parametre gönderdiğinzi Profile
sayfasında fazladan iş yükü olmadan route.params.user
diyerek kullanıcı verilerine ulaşmış olmak daha rahat görünüyor olabilir.
Aslında bu bir anti-pattern'dir. Bu tür veriler aslıdna global deponuzda olmalıdır. Çünkü bu verileri başka yerlerde çağırmak da isteyeceksiniz ve proje büyüdüğünde bu iletim yüzünden kod kalabalığı oluşacak, kodun uzunluğu nedeniyle okunabilirliği düşecek, hatalı veri gösterme olasılığı artacak vs.
Neden kullanıcıyı olduğu gibi aktarmak yerine sadece navigation.navigate('Profile', {userId:'jane'});
olarak göndermeniz gerektiğiyle ilgili uzun bir açıklama var ama sanırım zaten konuyu anladınız.
Dokümantasyonda Header bar Ayarları ve Header Butonları konuları vardı ama şu ana kadar attığımız temelle bunları dokümantasyondan anlamak kolaylaşmış olmalı. Bu konuları geçiyorum ve yukarıda anlatırken havada kalmış bir konu olan Nesting Navigators konusuna geçiyorum.
Nesting navigator'ler, bir navigator'un screen'i olarak başka bir navigator kullanmak anlamına geliyor.
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={ Home } />
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
Yukarıdaki örnekte Home
component'i bir tab navigator içeriyor. App
component'indeki stack navigator içine Home
component'i ile bir tab navigator yerleştirilmiştir:
Stack.Navigator
Home
(Tab.Navigator
)
Feed
(Screen
)Messages
(Screen
)Profile
(Screen
)Settings
(Screen
)Nesting navigator'ler, normal component'leri yerleştirmeye çok benzer. İstediğiniz davranışı elde etmek için genellikle birden çok navigator yerleştirmek gerekir.
Navigator'leri yerleştirirken aklınızda bulundurmanız gereken bazı şeyler var:
Örneğin, nesting navigator'de bir screen içindeyken geri butonuna basığınızda, üst öğe olarak başka bir navigator olsa bile nesting navigator'ün yığını içindeki bir önceki ekrana döner.
Örneğin, bir alt navigator içindeki header ayarları üst navigator'ü etkilemez.
Bu tip bir davranışı elde etmek istiyorsanız nested navigator'ler için ekran ayarları kılavuzuna bakın. Bir stack navigator içinde bir tab navigator oluşturuyorsanız ve stack navigator'un header'ında tab navigator'deki etkin ekranın başlığını göstermek istiyorsanız yararlı olabilir.
Örneğin, iç içe geçmiş bir navigator'daki bir screen'e aktarılan parametreler, o ekranın route
prop'undadır ve alt navigator'daki bir ekrandan erişilemez.
Bir alt ekrandan ana ekranın parametrelerine erişmeniz gerekiyorsa, parametreleri alt elemanlara (child'lere) iletmek için React Context'i kullanabilirsiniz.
Mesela bir nesting navigator içinde navigation.goBack()
dediniz. Sadece eğer bulunduğunuz navigator'daki yığının en üst sayfasındaysanız üst navigator'e dönersiniz. navigation.navigate()
gibi navigation işlemleri de benzer şekilde çalışır. Komutu verdiğiniz navigator içinde navigation işlemi gerçekleştirilir. Eğer bu navigator'un yığınında bu sayfa bulunamıyorsa üst navigator işlemi gerçekleştirmeye çalışır. Mesela yukarıdaki örnekde tab navigator'deki bir screen içinde navigate('Messages')
derseniz tab navigator sizi kendi içindeki Messages
screen'ine yönlendirir. Ama siz tutup da tab navigator screen'i içinde navigate('Settings')
derseniz tab navigator işi halletmeye çalışır ama böyle bir route barındırmadığı için işi üst navigator devralır ve tab navigator'den üstteki stack navigator'e geçip Settings
screen'ine yönlenmiş olursunuz.
Bu da performans sorunu yaratabiliyor. Navigator önce kendi içinde sayfayı arıyor, bulamayınca üst navigator'un yığınını kontrol ediyor. Sonra o yığında gideceğiniz sayfayı en üste alıyor vs vs.
Mesela bir drawer navigator içinde bir stack navigator varsa drawer'in openDrawer
, closeDrawer
, toggleDrawer
vb. fonksiyonları stack navigator'un navigator
prop'unda mevcuttur. Ama mesela drawer'ın üst navigator'u olarak bir stack navigator'unuz var diyelim. Bu durumda stack navigator içindeki screen'ler bu yöntemlere erişemezler. Çünkü bu yöntemler drawer navigator'ün içinde kalmıştır.
Benzer şekilde, stack navigator'de bir tab navigator varsa, stack navigator içindeki screen'ler navigation
prop'unda push
ve replace
fonksiyonlarını da alacaktır.
Eğer üst öğeden iç içe geçmiş alt navigator'lere/nested navigator'lere eylemler/action'lar göndermeniz gerekiyorsa navigation.dispatch
'ı kullanabilirsiniz:
navigation.dispatch(DrawerActions.toggleDrawer());
Örneğin bir tab navigator içine yerleştirilmiş bir stack navigator'unuz varsa stack navigator'deki screen'ler navigation.addEventListener
kullanılırken (tabPress
) gibi üst tab navigator tarafından yayılan olayları almazlar.
Ama siz yine de üst navigator'deki olayları almak için navigation.dangerouslyGetParent()
kullanabilirsiniz:
const unsubscribe = navigation
.dangerouslyGetParent()
.addListener('tabPress', (e) => {
// Do something
});
Mesela bir drawer navigator'un içinde bir stack navigator yerleştirdiğinizde, drawer'ın, stack navigator'unun header'inin üzerinde göründüğünü göreceksiniz. Ama bir drawer navigator'unu bir stack navigator'unun içine koyarsanız drawer, stack'ın header'inin altında görünecektir. Bu, navigator'unuzu nasıl yerleştireceğinize karar verrirken göz önünde bulundurmanız gereken önemli bir noktadır.
Uygulamanızda, muhtemelen istediğiniz davranışa bağlı olarak şu kalıpları kullanacaksınız:
Şu örneği düşünün:
function Root() {
return (
<Stack.Navigator>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Root" component={Root} />
</Drawer.Navigator>
</NavigationContainer>
);
}
Burada, App bileşeninizden Root stack'a gitmek isteyebilirsiniz.
navigation.navigate('Root');
Bu kod çalışınca Root bileşeni içindeki ilk ekran (Profile) gösterilir. Ancak bazen navigasyon sırasında gösterilmesi gereken ekranı kontrol etmek de isteyebilirsiniz. Bun uyapmak için screen adını parametrelerde geçebilirsiniz:
navigation.navigate('Root', { screen: 'Settings' });
Şimdi, navigasyon sırasında Profile yerine Settings ekranı görüntülenecek.
params
key'ini de geçirirseniz...
navigation.navigate('Root', { screen: 'Settings' , params: { user: 'jane' } });
Derinlemesine iç içe geçmiş ekranlar için de benzer bir yaklaşım var. Burada navigasyon için ikinci parametrenin sadece params
olduğuna dikkat edin. Böylece aşağıdaki gibi bi'şey yapabilirsiniz:
navigation.navigate('Root', {
screen: 'Settings',
params: {
screen: 'Sound',
params: {
screen: 'Media',
},
},
});
Yukarıdaki durumda, Settings ekranının içine yerleştirilmiş bir navigator içinde bulunan Sound screen'inin içine yerleştirilmiş bir Media screen'ine gidersiniz.
Aradığım bi'şeyleri bulmak için buraya kadar geldim ama bir türlü bulamadım...