react-native 2. 페이지 이동 (feat. tailwind)

Ho Kim·2022년 11월 26일
0

react-native

목록 보기
3/3

1. 프로젝트 세팅

지난 글과 동일하게 타입스트립트 리액트 네이티브를 세팅한다.

npx react-native init weather --template react-native-template-typescript 

페이지를 나눌 것이므로 먼저 폴더 세팅부터 해준다.

루트 위치에 src를 만들고, 그 내부에

  • api 통신 함수를 넣을 apis
  • 반복 사용되는 컴포넌트를 넣을 components
  • 렌더링 될 페이지를 넣을 pages
  • 공통적으로 사용함 함수를 담아둘 utils

폴더를 추가한다.

그리고 pages에 랜딩 페이지와 메인 페이지 파일을 추가한다.

2. 테일윈드 추가

tailwind 쓰다가 StyleSheet 쓰려니까 너무 귀찮아서 프로젝트에 tailwind을 추가하기로 했다.

npm모듈에서 검색해보니 주간 다운로드 기록이 twrnc가 가장 높고 최근 업데이트 기록도 있어서 twrnc를 쓰기로 했다.

사용방법은 아주 간단하다.

npm i twrnc

설치하고 일반 리액트에서 tailwind 모듈을 쓰는것과 동일한 방식으로 사용하면 된다.

// srcs/pages/Page_Landing.tsx

import React from 'react';
import {View, Text} from 'react-native';
import tw from 'twrnc';

const PageLanding = () => {
  return (
    <View style={tw`flex-1 bg-[#dfdfdf] items-center justify-center`}>
      <Text style={tw`text-[#51245f] font-bold text-[20]`}>Hello</Text>
    </View>
  );
};

export default PageLanding;

잘 뜨는지 확인하기 위해 App.tsx를 수정하자.

// App.tsx
import React from 'react';
import {SafeAreaView, StatusBar} from 'react-native';
import PageLanding from './srcs/pages/Page_Landing';
import tw from 'twrnc';

const App = () => {
  return (
    <SafeAreaView style={tw`flex-1`}>
      <StatusBar hidden />
      <PageLanding />
    </SafeAreaView>
  );
};

export default App;

SafeAreaView는 ios에서 둥근 부분 혹은 노치부분에 자동으로 패딩을 적용해준다고 해서 지금은 ios 테스트가 불가능하지만 나중을 대비해 그대로 사용해봤다.

안드로이드에서 테스트했을때는 일반 View처럼 나타난다.

이동할 대상 페이지도 만들어두자.

// srcs/pages/Page_Main.tsx
import React from 'react';
import {View, Text} from 'react-native';
import tw from 'twrnc';

const PageMain = () => {
  return (
    <View style={tw`flex-1 bg-[#dfdfdf] items-center justify-center`}>
      <Text style={tw`text-[#245f29] font-bold text-[20]`}>Wolrd</Text>
    </View>
  );
};

export default PageMain;

3. React Navigation 구성

페이지 이동을 위해 React Navigation을 사용할 것이다.

패키지를 설치한다.

npm install @react-navigation/native

3-1. 네비게이터 컨테이너

NavigationContainer는 탐색 트리를 관리하고 탐색 상태를 포함하는 구성 요소다.

이 구성 요소는 모든 네비게이터 구조를 래핑해야하므로 일반적으로 앱의 루트인 App.js에서 이 구성 요소를 렌더링하는 것이 좋다.

1) 모듈을 설치한다.

npm install react-native-screens react-native-safe-area-context

React Native 0.60 이상부터 연결은 자동이라 별도의 링크는 필요하지 않다고 한다.
(0.60이하일 경우는 홈페이지를 참고해서 세팅)

2) 안드로이드 설정을 해준다.

// android/app/src/main/java/<your package name>/MainActivity.java
...
import android.os.Bundle;

public class MainActivity extends ReactActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
  }
...

3-2. 네이티브 스택 네비게이터

모바일에서는 히스토리 개념이 없다.
대신, native stack navigator가 화면 간 전환과 탐색 기록 관리 기능을 제공한다.
사용자가 앱과 상호 작용할 때 앱이 탐색 스택에서 항목을 push/pop해서 사용자에게 다른 화면이 표시되도록 만든다.

1) 먼저 모듈을 설치한다.

npm install @react-navigation/native-stack

createNativeStackNavigator{Screen, Navigator} 객체를 반환하는 함수한다.
둘 다 네비게이터를 구성하는 데 사용되는 React 구성 요소인데, Navigator는 경로를 구성하기 위해 Screen을 자식으로 포함해야 한다.

2) App.tsx 구성

// App.tsx
import React from 'react';
import PageLanding from './srcs/pages/Page_Landing';
import PageMain from './srcs/pages/Page_Main';

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

const App = () => {
  const Stack = createNativeStackNavigator();
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Landing" component={PageLanding} />
        <Stack.Screen name="Main" component={PageMain} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

이렇게 하면 맨 처음 진입했을때 자동으로 첫번째 Stack.Screen의 컴포넌트가 렌더링 된다.

그런데 상단에 원하지 않았던 헤더가 표시되었다.
이 헤더는 자유롭게 커스터마이징 할 수 있어서 다른 페이지에서는 유용하게 쓸 수 있겠지만 랜딩 페이지에서는 무의미하므로 옵션을 줘서 제거한다.

// App.tsx
	...
        <Stack.Screen
          name="Landing"
          
          // 이 옵션을 추가한다.
          options={{headerShown: false}}
          
          component={PageLanding}
        />
    ...


헤더가 잘 설정되었다.

3) 페이지 자동 변경 구성

1초 뒤에 랜딩페이지가 자동으로 메인 페이지로 전환되도록 할 것이다.

// srcs/pages/Page_Landing.tsx
import React, {useEffect} from 'react';
import {View, Text} from 'react-native';
import tw from 'twrnc';
const PageLanding = ({navigation}) => {
  useEffect(() => {
    setTimeout(() => {
      navigation.navigate('Main');
    }, 1000);
  });

  return (
    <View style={tw`flex-1 bg-[#dfdfdf] items-center justify-center`}>
      <Text style={tw`text-[#51245f] font-bold text-[20]`}>Hello</Text>
    </View>
  );
};

export default PageLanding;

이렇게 하면 전환은 되긴 하는데 navigation가 any이 될 수 있다는 타입 오류를 띄운다.
타입 지정을 해주어야 한다.
리액트 네비게이터 타입 관련 글을 참고해 타입을 구성했다.

// @types/route.d.ts

declare type NavParamList = {
  Landing: undefined;
  Main: undefined;
};
declare type Props = NativeStackScreenProps<NavParamList, string>;

페이지명 뒤에 props로 넘겨줄 값의 타입을 지정해야하는데, 둘다 props 값이 없으므로 undefined로 지정했다.

App.tsx의 stack에 타입을 전달한다.

// App.tsx
...
  const Stack = createNativeStackNavigator<NavParamList>();
...

Page_Landing.tsxnavigation에 타입을 전달한다.

// srcs/pages/Page_Landing.tsx
...
const PageLanding = ({navigation}: Props) => {
...

이렇게 하면 오류 없이 페이지 전환이 잘 되는것을 확인 할 수 있다.

4) Props 전달

props 전달을 한번 해보자.
world 대신 앞에서 전달된 이름을 띄우기로 하자.

먼저 타입을 수정한다.

// @types/route.d.ts

declare type NavParamList = {
  Landing: undefined;
  Main: {name: string};
};
declare type Props = NativeStackScreenProps<NavParamList, string>;

Mainname이라는 string을 받는다고 명시했다.

이제 랜딩페이지에서 props를 같이 보낸다.

// srcs/pages/Page_Landing.tsx

...
const PageLanding = ({navigation}: Props) => {
  useEffect(() => {
    setTimeout(() => {
      
      // 이부분 변경
      navigation.navigate('Main', {
        name: 'hokim',
      });
      
    }, 1000);
  });
  
...

메인페이지에서 props를 받는다.

// srcs/pages/Page_Main.tsx
...
const PageMain = ({route}: Props) => {
  const {name} = route.params;
  return (
    <View style={tw`flex-1 bg-[#dfdfdf] items-center justify-center`}>
      <StatusBar hidden={false} />
      <Text style={tw`text-[#245f29] font-bold text-[20]`}>{name}</Text>
    </View>
  );
};

export default PageMain;

이렇게 하면 메인 화면에서 보낸 hokim이 나타난다.

5. 이전 히스토리 지우기

랜딩 페이지에서 메인 페이지로 간 후, 뒤로가기 버튼을 누르면 랜딩 페이지로 이동한다.
랜딩 페이지로 갈 수 없도록 막아야한다.

CommonActions로 스택 기록을 초기화 할 것이다.

// srcs/pages/Page_Landing.tsx
...
import {CommonActions} from '@react-navigation/native';

const PageLanding = ({navigation}: Props) => {
  useEffect(() => {
    setTimeout(() => {
      
      navigation.dispatch(
        CommonActions.reset({
          index: 1,
          routes: [
            {
              name: 'Main',
              params: {name: 'hokim'},
            },
          ],
        }),
      );
      
    }, 1000);
  }, []);
  
...

dispatch 메서드는 작업 생성자(CommonActions)를 통해 탐색 상태를 수동으로 업데이트한다.
routes에 이동해야 할 페이지와 props를 지정하고 index를 1로 해 첫번째 route로 페이지를 이동시킨다.

이렇게 하면 히스토리가 없기 때문에 헤더의 뒤로가기 버튼이 사라지고, 기기의 뒤로가기 버튼을 누르면 앱이 종료되게 된다.





상세 코드는 링크 참조:
https://github.com/hokim2407/react-native-nav/commit/9fd91863372d1a7d4b0ccd35cc3f4ac302f591f2

0개의 댓글