react native에서 navigation을 사용해 페이지를 이동할 때, 이동할 페이지로 특정 데이터를 넘겨야할 때가 있다. 일반적으로 다른 컴포넌트에 데이터를 제공하는 방법은 크게 prop을 사용하는 방법과 전역상태를 설정해 공유하는 방법이 있는데, navigation을 사용할 때는 두가지 방법 모두 적절하지 않다.
navigation으로 이동 가능한 각 화면들은 모두 navigator라는 고차 컴포넌트에 묶여있기 때문에 직접적으로 prop을 전달할 수도 없을 뿐더러, state를 사용해 전달하려고 해도 prop드릴링, 또는 전역 상태 관리가 동반되어야한다. 또한 상태관리 라이브러리를 사용한다고 해도 하나의 페이지에서 다른 페이지로 일부 데이터를 넘기는데 매번 새로운 상태를 선언하고 클린업해주는 과정은 너무 과하다고 생각되기도 한다.
이럴 때 사용하는 것이 바로 useRoute라는 훅이다. 다른 페이지로 이동할 때 사용하는 navigate 함수와 useRoute를 사용하면 함수에 인자를 넘겨주듯이 다른 페이지로 데이터를 넘기고, 받을 수 있다.
//Home
...
const {navigate} = useNavigation();
const id = "1";
const goToDetail = () => navigate('detail',id);
...
//Detail
...
const {params:id} = useRoute();
console.log(id); //"1"
...
위와 같이 navigate 함수의 두번째 argument로 넘겨줄 데이터를 입력하면, 다른 컴포넌트에서 useRoute를 이용해 데이터를 받아올 수 있게 된다.
하지만 여기에 TS를 적용하면 한가지 에러를 마주하게 된다. 아무런 타입 설정 없이 useRoute를 사용하면 params의 타입이 object로 고정되는 것이다.
const {params} = useRoute();
//const params: Readonly<object | undefined>
params를 아까와 같이 string타입인 id로 넘겨서 사용해봐도 정작 id를 사용할 때는 object타입은 string타입에 할당할 수 없다는 에러가 출력되거나, object형태로 넘겼다고 해도 아이템을 꺼내서 쓰려면 타입 에러가 발생하는 일이 일어난다.
const id = params?.id;
//Property 'id' does not exist on type 'object'
이 문제를 해결하기 위해서는 useRoute의 generic으로 받아올 params의 타입을 미리 제공해줘야 한다.
import {RouteProp, useNavigation, useRoute} from '@react-navigation/native';
type ParamList = {
sampleType: {
id:string
};
};
...
const {params} = useRoute<RouteProp<ParamList, 'sampleType'>>();
...
위와 같이 RouteProp을 import해서 useRoute를 사용하면 된다.
더불어 navigate를 사용할 때도 react native 버전업이 되면서 인수의 타입이 never로 고정되는 에러가 발생하는데, 이 문제도 이번과 유사하게 useNavigation을 사용하는 시점에 제네릭으로 타입을 미리 선언해주면 된다.
useRoute 타입 설정: https://stackoverflow.com/questions/60896364/react-native-with-typescript-how-to-use-the-useroute-from-react-navigation-na
useNavigation 타입 설정: https://stackoverflow.com/questions/68667766/react-native-typescript-string-is-not-assignable-to-parameter-of-type-never