Kurs React Native · Moduł 3: Nawigacja

Stack Navigation - Podwodne Korytarze

3 min czytania ·
W tej lekcji8

Witaj w korytarzach Atlantydy! Posejdon wprowadza cię w tajniki nawigacji - systemu, który pozwala przemieszczać się między ekranami aplikacji jak przez korytarze podwodnego pałacu.

Czym jest React Navigation?

React Navigation to najpopularniejsza biblioteka nawigacyjna dla React Native. Pozwala tworzyć różne typy nawigacji: stosową (Stack), zakładkową (Tab), szufladową (Drawer) i wiele innych.

Instalacja React Navigation w Expo

# Instalacja core
npx expo install @react-navigation/native

# Zależności dla Expo
npx expo install react-native-screens react-native-safe-area-context

# Stack Navigator
npx expo install @react-navigation/stack
npx expo install react-native-gesture-handler

# Lub Native Stack (zalecany, szybszy)
npx expo install @react-navigation/native-stack

Podstawowa konfiguracja

// App.tsx
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

// Definiujemy typy dla parametrów nawigacji
type RootStackParamList = {
  Home: undefined;
  Details: { itemId: number; title: string };
  Profile: { userId: string };
};

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen
          name="Home"
          component={HomeScreen}
          options={{ title: 'Pałac Atlantydy' }}
        />
        <Stack.Screen
          name="Details"
          component={DetailsScreen}
          options={{ title: 'Komnata Szczegółów' }}
        />
        <Stack.Screen
          name="Profile"
          component={ProfileScreen}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Ekran główny z nawigacją

import { NativeStackScreenProps } from '@react-navigation/native-stack';

type HomeScreenProps = NativeStackScreenProps<RootStackParamList, 'Home'>;

function HomeScreen({ navigation }: HomeScreenProps) {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Witaj w Atlantydzie!</Text>

      {/* Nawigacja do ekranu bez parametrów */}
      <Pressable
        style={styles.button}
        onPress={() => navigation.navigate('Details', {
          itemId: 42,
          title: 'Komnata Posejdona'
        })}
      >
        <Text style={styles.buttonText}>Wejdź do komnaty</Text>
      </Pressable>

      {/* Użycie push zamiast navigate */}
      <Pressable
        style={styles.button}
        onPress={() => navigation.push('Details', {
          itemId: 43,
          title: 'Komnata Trytona'
        })}
      >
        <Text style={styles.buttonText}>Odkryj kolejną komnatę</Text>
      </Pressable>
    </View>
  );
}

Różnica między navigate a push

// navigate - jeśli już jesteś na tym ekranie, nic nie robi; w przeciwnym razie dodaje go na stos
// (od React Navigation 7 nie wraca do ekranu niżej na stosie, do tego służy popTo)
navigation.navigate('Details', { itemId: 1 });

// push - zawsze dodaje nowy ekran na stos (nawet jeśli taki sam)
navigation.push('Details', { itemId: 2 });

// Przykład: galeria obrazów gdzie każdy obraz otwiera Details
// push pozwala mieć wiele ekranów Details na stosie

Odbieranie parametrów

type DetailsScreenProps = NativeStackScreenProps<RootStackParamList, 'Details'>;

function DetailsScreen({ route, navigation }: DetailsScreenProps) {
  // Parametry są typowane dzięki RootStackParamList
  const { itemId, title } = route.params;

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{title}</Text>
      <Text>ID komnaty: {itemId}</Text>

      {/* Powrót do poprzedniego ekranu */}
      <Pressable onPress={() => navigation.goBack()}>
        <Text>Wróć</Text>
      </Pressable>

      {/* Powrót do pierwszego ekranu na stosie */}
      <Pressable onPress={() => navigation.popToTop()}>
        <Text>Wróć do pałacu</Text>
      </Pressable>
    </View>
  );
}

Opcje nagłówka

<Stack.Screen
  name="Details"
  component={DetailsScreen}
  options={({ route }) => ({
    title: route.params.title,
    headerStyle: {
      backgroundColor: '#1a5276',
    },
    headerTintColor: '#fff',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
    // Przycisk w nagłówku
    headerRight: () => (
      <Pressable onPress={() => alert('Info!')}>
        <Text style={{ color: '#fff', marginRight: 10 }}>ℹ</Text>
      </Pressable>
    ),
  })}
/>

Dynamiczne opcje z navigation.setOptions

function DetailsScreen({ route, navigation }: DetailsScreenProps) {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // Dynamiczna zmiana tytułu
    navigation.setOptions({
      title: `Komnata #${route.params.itemId}`,
      headerRight: () => (
        <Text style={{ color: '#fff' }}>Odwiedziny: {count}</Text>
      ),
    });
  }, [navigation, route.params.itemId, count]);

  return (
    <View>
      <Pressable onPress={() => setCount(c => c + 1)}>
        <Text>Zwiększ licznik</Text>
      </Pressable>
    </View>
  );
}

Stack Navigation to podstawa nawigacji w React Native. Działa jak stos kart - każdy nowy ekran jest kładzieny na wierzch, a powrót zdejmuje górną kartę.

Kod do tej lekcji: App.tsx
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

function HomeScreen({ navigation }) {
  return (
    <View style={styles.screen}>
      <Text style={styles.title}>Pałac Atlantydy</Text>
      {/* Przejdź do ekranu 'Details' i przekaż parametr itemId */}
      <Button
        title="Wejdź do komnaty"
        onPress={() => navigation.navigate('Details', { itemId: 42 })}
      />
    </View>
  );
}

function DetailsScreen({ route }) {
  const { itemId } = route.params;
  return (
    <View style={styles.screen}>
      <Text style={styles.title}>Komnata #{itemId}</Text>
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      {/* TODO: dodaj <Stack.Navigator> z propem initialRouteName="Home" */}
      {/* TODO: wewnątrz dodaj <Stack.Screen name="Home" component={HomeScreen} /> */}
      {/* TODO: dodaj drugi <Stack.Screen name="Details" component={DetailsScreen} /> */}

    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#1a5276',
    gap: 16,
  },
  title: {
    fontSize: 22,
    color: '#fff',
    fontWeight: '600',
  },
});

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Co musi opakowywać całą nawigację w React Navigation?

  2. 2. Jaka jest różnica między navigation.navigate() a navigation.push()?

To 2 z 4 pytań do tej lekcji. Pozostałe rozwiążesz w grze.

Zadania praktyczne w grze

  • Układanie w pionie

    Uporządkuj elementy Stack Navigator od zewnętrznego do wewnętrznego:

  • Klikanie w kolejności

    Kliknij elementy w kolejności przekazywania parametrów do ekranu:

  • Edytor kodu

    Uzupełnij kod Stack Navigator.

Przydatne artykuły