React Native/React Native_study

[리액트 네이티브를 다루는 기술 #7] 5장 리액트 내비게이션으로 여러 화면 관리하기 (p.215 ~ 243)

bocoder
728x90
반응형

@ List

* 5.1 설치 및 적용하기

** 5.1.1 의존 패키지 설치하기

** 5.1.2 라이브러리 적용하기

* 5.2 기본적인 사용법

** 5.2.1 네이티브 스택 내비게이터

** 5.2.2 스크린 이동하기

** 5.2.3 라우트 파라미터

** 5.2.4 뒤로가기

** 5.2.5 헤더 커스터마이징하기

 

@ Note

1. react-navigation 의존 패키지 설치

// 모듈 설치
yarn add @react-navigation/native

// 의존 라이브러리 설치
yarn add react-native-screens react-native-safe-area-context

 - reference : https://reactnavigation.org/docs/getting-started

 

2. 주요 함수

 - navigation.push() : 새로운 화면이 스택이 쌓여가면서 전환됨, 뒤로가기 클릭 시 이전 화면 열림
 - navigation.navigate() : 새로운 화면이 현재 화면과 같으면 화면을 쌓지않고 파라미터만 변경함, 뒤로가기 클릭 시 홈 화면 열림
 - navigation.pop() : 뒤로가기
 - navigation.popToTop() : 처음으로 가기

 

3.  화살표 함수 사용 시 주의점

 - 화살표 함수 호출 시 바로 반환하는 경우는 중괄호와 return 생량 가능
  > const add = (a, b) => { return a + b };
  > const add = (a, b) => a + b;
 - 바로 반환하는 값이 객체 타입이면 객체를 소괄로 감싸줘야 함
  > const createObject = (a, b) => { return {a, b}; };
  > const createObject = (a, b) => ({a, b})

 

4. navigation, route 파라미터의 사용

 - HomeScreen({navigation}) 에서 navigation.push('Detail', {id: 1})} 로 id값 넘겨줌

 - DetailScreen({route}) 에서 route.params.id 로 id 값 불러옴

  > key : 화면의 고유 ID로 새로운 화면이 나타날 때 자동으로 생성됨

  > name : 화면의 이름으로 App 컴포넌트에서 네이티브 스택 내비게이터를 설정할 때 지정한 이름

  > params : 화면 전환 시 지정한 라우트 파라미터

 -  reference : https://reactnavigation.org/docs/params

DetailScreen 에 넘어오는 route, navigation Props의 정보

 

5. Header 커스터마이징 시 Options Props

  > Stack.Navigatior 의 screenOptions={} : 모든 화면에 공통으로 적용할 때

  > Stack.Screen 의 options={} : 개별 화면에 적용할 때

 - reference : https://reactnavigation.org/docs/native-stack-navigator#options

 

@ Result

01234
ios / android - Stack 전환 테스트

 

012345
ios / android - Header 커스터마이징

 

# App.js

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import DetailScreen from './screens/DetailScreen';
import {View, Text, TouchableOpacity, SafeAreaView} from 'react-native';
import HeaderlessScreen from './screens/HeaderlessScreen';

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="Home"
        // Screen에 공통적으로 적용 시
        screenOptions={{
          headerShown: false,
        }}>
        <Stack.Screen
          name="Home"
          component={HomeScreen}
          options={{
            title: '홈',
            // Header 블록에 대한 스타일
            headerStyle: {
              backgroundColor: '#29b6f6',
            },
            // Header의 텍스트, 버튼들 색상
            headerTintColor: '#ffffff',
            // 타이틀 텍스트의 스타일
            headerTitleStyle: {
              fontWeight: 'bold',
              fontSize: 20,
            },
          }}
        />
        <Stack.Screen
          name="Detail"
          component={DetailScreen}
          options={{
            // android 좌측 화살표 아이콘 제거
            // headerBackVisible: false,
            headerLeft: ({onPress}) => (
              <TouchableOpacity onPress={onPress}>
                <Text>Left</Text>
              </TouchableOpacity>
            ),
            headerTitle: ({children}) => (
              <View>
                <Text>{children}</Text>
              </View>
            ),
            headerRight: () => (
              <View>
                <Text>Right</Text>
              </View>
            ),
          }}
        />
        <Stack.Screen
          name="Headerless"
          component={HeaderlessScreen}
          options={{
            headerShown: false,
          }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

 

# screens > HomeScreen.js

import React, {useEffect} from 'react';
import {View, Button} from 'react-native';
import HeaderlessScreen from './HeaderlessScreen';

function HomeScreen({navigation}) {
  //   useEffect(() => {
  //     navigation.setOptions({title: '홈'});
  //   }, [navigation]);

  return (
    <View>
      <Button
        title="Detail 1 열기"
        // onPress={() => navigation.navigate('Detail')}
        onPress={() => navigation.push('Detail', {id: 1})}
      />
      <Button
        title="Detail 2 열기"
        onPress={() => navigation.push('Detail', {id: 2})}
      />
      <Button
        title="Detail 3 열기"
        onPress={() => navigation.push('Detail', {id: 3})}
      />
      <Button
        title="Headerless 열기"
        onPress={() => navigation.push('Headerless', {id: 4})}
      />
    </View>
  );
}

export default HomeScreen;

 

# screens > DetailScreen.js

import React, {useEffect} from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';

function DetailScreen({route, navigation}) {
  useEffect(() => {
    navigation.setOptions({
      title: `상세 정보 - ${route.params.id}`,
    });
  }, [navigation, route.params.id]);

  return (
    <View style={styles.block}>
      <Text style={styles.text}>id: {route.params.id}</Text>
      <View style={styles.buttons}>
        <Button
          title="다음"
          // 이전 화면과 동일하면 스택을 쌓지 않고 파라미터만 변경함
          // onPress={() => navigation.navigate('Detail', {id: route.params.id + 1})}
          onPress={() => navigation.push('Detail', {id: route.params.id + 1})}
        />
        <Button title="뒤로가기" onPress={() => navigation.pop()} />
        <Button title="처음으로" onPress={() => navigation.popToTop()} />
      </View>
    </View>
  );
}

export default DetailScreen;

const styles = StyleSheet.create({
  block: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 48,
  },
  buttons: {
    flexDirection: 'row',
  },
});

 

# screens > HeaderlessScreen.js

import React from 'react';
import {View, Text, Button} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';

function HeaderlessScreen({navigation}) {
  return (
    <SafeAreaView>
      <View>
        <Text>Header가 없네?</Text>
        <Button onPress={() => navigation.pop()} title="뒤로가기" />
      </View>
    </SafeAreaView>
  );
}

export default HeaderlessScreen;

 

728x90
반응형