RN 7

Laejun Kim·2024년 11월 4일

React Native

목록 보기
3/6

Components

FlatList

numColumns 속성을 이용하면 컬럼의 수를 조절하여 grid 같은 것을 만들 수 있다.

const renderCategoryItem = (itemData) => {
  return (
    <CategoryGridTile title={itemData.item.title} color={itemData.item.color} />
  );
};

const CategoriesScreen = () => {
  return (
    <FlatList
      data={CATEGORIES}
      keyExtractor={(item) => item.id}
      renderItem={renderCategoryItem}
      numColumns={2}
    />
  );
};

React Navigation

초기설정

RN 에서 라우팅과 네비게이션을 하기 위해 사용하는 패키지이다.
공식홈페이지에도 'Routing and Navigation for Expo and React Native apps' 라고 설명되어있다. 특히 Expo 프로젝트에서 더 사용이 쉽다는 장점이 있다.

설치는 아래의 명령어로
npm install @react-navigation/native

이후 다음의 명령어로 의존성도 마저 설치해준다
npx expo install react-native-screens react-native-safe-area-context
위 명령어는 expo 프로젝트에서 사용하는 명령어이고 bare RN 프로젝트에서는 다른 명령어를 써야 하는데 이는 공식 docs 에서 확인 가능하다.

React Navigation은 컴포넌트 기반의 라이브러리이므로 네비게이션 구성을 할 수 있는 다양한 컴포넌트를 제공한다.

설치가 잘 되었으면 App.jsx 에서 NavigationContainer를 import 하는 것으로 시작하자. 네비게이션 기능을 활용할 부분을 감싸준다고 보면 되는데 이미 react-router-dom 이나 다른 상태관리 라이브러리에서 익숙한 패턴이다.

//App.jsx
import { StatusBar } from "expo-status-bar";
import { StyleSheet } from "react-native";
import CategoriesScreen from "./screens/CategoriesScreen";
➡️import { NavigationContainer } from "@react-navigation/native";

export default function App() {
  return (
    <>
      <StatusBar style="light" />
     ➡️<NavigationContainer>
        <CategoriesScreen />
     ➡️</NavigationContainer>
    </>
  );
}

const styles = StyleSheet.create({});

네비게이터

Drawer, Stack, Native Stack, Bottom Tab 등 다양한 종류가 있다.
먼저 Native Stack 부터 알아보자.

npm install @react-navigation/native-stack

설치가 되고나면 내비게이터와 네비게이터에 포함될 화면을 등록해야 한다.

createNativeStackNavigator 라는 이름의 함수를 import 한뒤 이것을 이용하여 Stack 객체를 생성한뒤 설정을 해준다.

미리 생성해둔 NavigationContainer 사이에 Stack.Navigator를 만들고 그안에 Stack.Screen 컴포넌트를 넣고 실제 화면이 될 컴포넌트를 배정하면된다. 이때 Stack.Screen 컴포넌트는 name 과 component를 받는데 이들은 각각 이름과 그 화면을 뿌릴 컴포넌트를 의미한다. 컴포넌트를 배정할때는 jsx 요소로 넣는 것이 아니고 그냥 그 컴포넌트 함수에 대한 pointer 로 넣는 것에 주의.

글로 설명하면 복잡하지만 예시를 보면 어렵지 않게 이해할 수 있다.

import { StatusBar } from "expo-status-bar";
import { StyleSheet } from "react-native";
import CategoriesScreen from "./screens/CategoriesScreen";
import { NavigationContainer } from "@react-navigation/native";
➡️import { createNativeStackNavigator } from "@react-navigation/native-stack";

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <>
      <StatusBar style="light" />
      <NavigationContainer>
        ➡️<Stack.Navigator>
          ➡️<Stack.Screen name="MealsCategories" component={CategoriesScreen} />
        ➡️</Stack.Navigator>
      </NavigationContainer>
    </>
  );
}


위 예시까지 적용된 모습의 스크린샷인데, MealsCategories 라는 (내가 직접 만든적 없는)헤더가 생겼고, app.json 에서 어두운 색으로 설정해두었던 backgroundColor도 해제된 모습을 확인할 수 있다. 이런 변화는 모두 React Navigation 에서 기본적으로 설정해둔 값이 적용된 것. SafeArea까지 섬세하게 설정된 모습이다.

내비게이터에 screen 추가하기

Stack.Screen 을 하나 추가하고 component 에 해당 화면 컴포넌트를 등록해 주면 된다.

        <Stack.Navigator>
          <Stack.Screen name="MealsCategories" component={CategoriesScreen} />
        ➡️<Stack.Screen name="MealsOverview" component={MealsOverviewScreen} />
        </Stack.Navigator>

그리고 그 화면으로 이동하는 조건에 대한 설정을 해주어야만 한다. '뭘 눌렀을때 어디로 갈지' 에 대한 설정을 해야 한다는 의미이다.

StackScreen 에 component로 제공된 컴포넌트들은 React Navigation에 의해 자동으로(별도로 prop 지정이 필요없다!) 특별한 navigation prop을 받게 되는데 이것을 이용하여 화면 이동을 구현할 수 있다.

navigation prop은 navigate 함수를 내장하고 있고, 이 navigate 함수를 이용하여 이동할 페이지 이동을 규정한다. navigate 의 첫 인자는 이동할 화면의 이름인데 이 이름은 앞서 Stack.Screen의 name 에 적은 이름을 그대로 사용해야 한다.

Pressable 을 눌렀을때 MealsOverviewScreen 으로 이동하고자 하는 상황을 생각해보자. 먼저 Pressable 에 onPress 속성을 주고, 여기에 핸들러 함수를 하나 만든 뒤, 해당 핸들러 함수에서 navigation.navigate() 를 호출하고, navigate 의 인자로 이동하고자 하는 페이지의 이름을 넣어주면 된다.

import { StyleSheet, Text, View, FlatList } from "react-native";
import { CATEGORIES } from "../data/dummy-data";
import CategoryGridTile from "../components/CategoryGridTile";

//navigation prop을 꺼내 쓸수 있는 이유는 
//CategoriesScreen이 Stack.Screen에 구성되어있기 때문이다.
const CategoriesScreen = ({ ➡️navigation }) => {
  const renderCategoryItem = (itemData) => {
  ➡️function pressHandler() {
      ➡️navigation.navigate("MealsOverview");
    }
    return (
      <CategoryGridTile
        title={itemData.item.title}
        color={itemData.item.color}
      ➡️onPress={pressHandler}
      />
    );
  };

  return (
    <FlatList
      data={CATEGORIES}
      keyExtractor={(item) => item.id}
      renderItem={renderCategoryItem}
      numColumns={2}
    />
  );
};

export default CategoriesScreen;

const styles = StyleSheet.create({});

위 예시에서 한가지 유의할 점은 FlatList를 사용하고 있기 때문에 jsx 리턴부가 renderItem 의 renderCategoryItem 함수에 나뉘어 있다는 점. 그래도 로직 자체는 그렇게 어렵지 않다.

제대로 설정이 되었다면 Pressable 을 눌렀을때 지정한 페이지로 이동이 가능해지고, 자동으로 Back 버튼도 생긴다! 각 플랫폼에 맞는 애니메이션은 덤이다! 여담으로 Native Stack 에서 Native가 바로 이렇게 각 플랫폼에 native 로 존재하는 애니메이션과 양식을 활용하기 때문에 native stack 이라고 이름 붙은 것이다. Stack 은 네이티브 동작을 흉내내기 때문에 성능이 더 떨어질 수 있다고 한다. Native Stack 은 네이티브 동작을 흉내내는 것이 아니라 그냥 그대로 사용한다.

보통은 네이티브 스택을 스택보다 선호합니다. -Max

useNavigation

위에서 살펴본 경우는 navigation prop을 꺼내 쓸수 있는 경우이다. 그렇지만 모종의 이유로 그것이 불가능 할 때는 어떻게 해야할까?

그런 경우에 사용하는 훅이 useNavigation 이다.

import { useNavigation } from "@react-navigation/native";
이 훅은 '모든' 컴포넌트 함수에서 사용 가능하며, Stack.Screen에 구성되어 있지 않아도 무관하다.

import { Pressable, StyleSheet, Text, View, Platform } from "react-native";
import React from "react";
➡️import { useNavigation } from "@react-navigation/native";

const CategoryGridTile = ({ title, color, onPress }) => {

    ➡️const navigation = useNavigation();
    
  return (
    <View style={styles.gridItem}>
      <Pressable
        android_ripple={{ color: "#ccc" }}
        style={({ pressed }) => [
          styles.button,
          pressed ? styles.buttonPressed : null,
        ]}
        onPress={onPress}
      >
        <View style={[styles.innerContainer, { backgroundColor: color }]}>
          <Text style={styles.title}>{title}</Text>
        </View>
      </Pressable>
    </View>
  );
};

export default CategoryGridTile;

이런식으로 navigation 객체-navigate 메서드가 들어있다-를 바로 꺼내서 활용하는 것도 가능하다는 것을 꼭 기억해 두어야 한다.

화면 사이에 data 전달하기

앞서 navigate 메서드에 대해서 다루면서 해당 메서드의 첫번째 인자는 이동할 화면의 '이름'이라는 것을 익혔다.

이제 이 메서드에 두번째 인자로 객체를 전달하고 이 객체 안에 이동할 화면에 전달해야하는 params를 구성할 수 있다.

      navigation.navigate("MealsOverview", {
        categoryId: itemData.item.id,
      });

이런식으로 두번째 인자로 전달한 객체 안에 categoryId 라는걸 정해 두면, 이것을 이동할 화면에서 route prop 으로 받아서 params 객체 안에서 확인할수 있다.

const MealsOverviewScreen = ({ ➡️route }) => {
➡️const catId = route.params.categoryId;
  
  return (
    <View style={styles.container}>
      <Text>Meals Overview Screen - {catId}</Text>
    </View>
  );
};

route 도 Stack.Screen에 등록된 컴포넌트에 자동 전달되는 prop이며 이에 대한 상세는 공식 문서에서 확인 가능하다.

Navigation prop 문서
Route prop 문서

useRoute

useNavigation 과 완전히 동일한 패턴이다. route prop 을 직접 받지 못하는 경우(Stack.Screen에 등록되지 않은 경우) route 객체에 접근할 수 있게 해준다. useNavigation 과 동일하게
import { useRoute } from "@react-navigation/native";
에서 import 하여 사용한다.

0개의 댓글