React Native Navigation + Typescript 사용하기

JeongHan Lee·2023년 10월 30일
post-thumbnail

React Native + Typescript 환경에서 작업 중 나온 문제 중 일부를 기록한다.

웹이나 앱에서 한개의 화면을 사용하는 프로덕트는 극히 일부이다.
그렇기에 당연히 nav를 포함한 기능이 들어가야하는데 개인적으로 RN에서의 라우팅 기능이 사용감이 되게 별로였고 고생도 많이 했다.
다른분들에게도 도움이 되었으면 하는 마음에 기록한다.

기본 사용법

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

// ~~

const Stack = createNativeStackNavigator();

<NavigationContainer>
  <Stack.Navigator initialRouteName="Home">
    <Stack.Screen name="Home" component={Home} options={{headerShown: false}} />
    <Stack.Screen
      name="AddEventModal"
      component={AddEventModal}
      options={{presentation: 'modal', headerShown: false}}
    />
  </Stack.Navigator>
</NavigationContainer>;

위처럼 NavigationContainer를 부모로 Stack을 감싸 사용하는 형태이다.
위 화면에서는 type이 없어도 아무런 이상이 없지만 진짜 문제는 다른곳에서 발생한다.

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

const Component = () => {
  const router = useNavigation();

  return (
    <TouchableOpacity onPress={() => router.navigate('AddEventModal')}>
      <View style={styled.container}>
        <Text style={styled.text}>버튼</Text>
      </View>
    </TouchableOpacity>
  );
};

나는 Component의 Props로 navigation을 받는게 아니고 직접 useNavigation 함수를 호출해서 route를 구현하고 싶었다.

솔직히 라우팅이 필요할때마다 prop을 받아야 한다는게 너무 구렸다

하지만 위처럼 사용하면 작동은 잘 되지만 TS에서 에러가 나왔다.

에러 1

No overload matches this call.
  Argument of type '[string]' is not assignable to parameter of type 'never'.
  Overload 2 of 2, '(options: never): void', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'never'.

string 형식을 never 형식에 포함 할 수 없다는 것.

말 그대로는 이해 못하지만 대충 검색을 해보니 대충 이해는 갔다.
웹에서 라우팅할때 쿼리를 포함해 보내는 경우가 있는데 같은 경우였다.
여기서는 쿼리가 필요한지 아닌지 모르니까 타입을 정의해서 알려달라는 의미였다.

공식문서를 뒤져 해결법을 찾아냈지만 진짜 난관은 한번 더 있었는데...

문제해결 1

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

// ~~

export interface NavigatorCallback {
  Home: undefined;
  AddEvent: undefined;
};

const Stack = createNativeStackNavigator<NavigatorCallback>();

<NavigationContainer>
  <Stack.Navigator initialRouteName="Home">
    <Stack.Screen
      name="Home"
      component={Home}
      options={{headerShown: false}}
    />
    <Stack.Screen
      name="AddEventModal"
      component={AddEventModal}
      options={{presentation: 'modal', headerShown: false}}
    />
  </Stack.Navigator>
</NavigationContainer>

위와 같이 type을 지정해서 넣어줬더니 아래와 같은 문제로 변했다.

Type 'NavigatorCallback' does not satisfy the constraint 'ParamListBase'.

이것때문에 진짜 미쳐버리는줄 알았다.

문제해결 2

나는 평소 타입을 지정할때 interface를 주로 사용하는데 이 경우도 당연히 interface를 사용했다.
근데 혹시나 싶어서 type으로 바꿔서 넣어보니 해결됐다..
코드는 아래와 같다.

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

// ~~

export type NavigatorCallback = {
  Home: undefined;
  AddEvent: undefined;
};

const Stack = createNativeStackNavigator<NavigatorCallback>();

<NavigationContainer>
  <Stack.Navigator initialRouteName="Home">
    <Stack.Screen
      name="Home"
      component={Home}
      options={{headerShown: false}}
    />
    <Stack.Screen
      name="AddEventModal"
      component={AddEventModal}
      options={{presentation: 'modal', headerShown: false}}
    />
  </Stack.Navigator>
</NavigationContainer>

router push / navigate를 사용할땐 아래와 같이 사용하면 된다.

import {useNavigation} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {NavigatorCallback} from '@/components/layout/Navigator';

const Component = () => {
  const router =
    useNavigation<NativeStackNavigationProp<NavigatorCallback, 'AddEventModal'>>();

  return (
    <TouchableOpacity onPress={() => router.navigate('AddEventModal')}>
      <View style={styled.container}>
        <Text style={styled.text}>버튼</Text>
      </View>
    </TouchableOpacity>
  );
};

처음 type과 interface는 큰 차이가 없다고 알고있었는데 이걸로 에러가 나니 예상조차 못하고 엄청 헤맸다

Reference * https://reactnavigation.org/docs/typescript

0개의 댓글