모든 내용은 React Native Navigation 공식 문서의 기초 섹션 내용을 정리하였습니다.
https://reactnavigation.org/docs/getting-started
React Native Navigation을 사용하는 이유
웹 환경에서는 브라우저에 글로벌한 히스토리 스택이 존재하여 사용자가 뒤로 가기 버튼을 누를 경우 이전에 방문했던 페이지로 되돌아갈 수 있습니다. 하지만 React Native에서는 웹 브라우저처럼 전역 기록 스택에 대한 기능이 없기 때문에 사용자의 화면 이동을 관리하기 위해서 React Native Navigation이 필요합니다. 더욱이 React Native Navigation를 사용하면 웹 브라우저와 다르게 기본 스택 탐색기가 스택을 탐색할 때 Android 및 iOS 네이티브 단의 애니메이션을 사용할 수 있습니다.
기본적인 이해
- createNativeStackNavigator()
Navigation Stack을 만들 수 있는 함수입니다.
만들어진 Stack 내에 정의한 스크린 간 기록 히스토리를 쌓을 수 있습니다.
Screen과 Navigator라는 두 속성이 포함된 객체를 반환하며
Navigator를 선언할 때는 Screen 요소를 포함해야만 합니다.
- NavigationContainer
탐색 트리를 관리하고 탐색 상태를 포함하는 컴포넌트입니다.
이 컴포넌트는 각 화면을 정의하는 Screen 컴포넌트들의 최상단에 위치하여야 합니다.
일반적으로 App.js에서 내보낸 구성 요소인 앱의 루트에 이 구성 요소를 렌더링합니다.
- Screen 컴포넌트
는 탐색에 사용할 경로 이름에 해당하는 name 속성과 실제로 렌더링 할 컴포넌트를 가리키는 component 속성이 포함돼야 합니다. 추가적으로 Screen 컴포넌트에서 제공하는 옵션들을 사용하고 싶다면 options 속성을 수정해 커스텀할 수 있습니다.
각 화면 간 Props를 전달하는 방법
각 Screen에 props를 전달하고 싶을 때 2가지 방법을 사용할 수 있습니다.
1. React Context를 사용하여 내비게이터를 컨텍스트 제공자에 래핑 하여 데이터를 전달하는 방법 ( 권장 )
2. Screen에 render callback을 사용하는 방법
<Stack.Screen name="Home">
{(props) => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
기본적으로 React Navigation은 불필요한 렌더링을 방지하기 위해 화면 구성 요소에 최적화를 적용합니다.
만약 2번 방법인 Render Callback을 사용하면 이러한 최적화가 적용되지 않기 때문에 성능 문제를 방지하기 위해 Screen 구성 요소에 React.memo 또는 React.PureComponent를 사용해야 합니다.
화면 간 이동하는 방법
웹 브라우저와 비교하여 이해를 해보면 웹 브라우저에서는 화면 간 이동을 위해 아래와 같이 할 수 있습니다.
<a href="details.html">Go to Details</a>
or
<a
onClick={() => {
window.location.href = 'details.html';
}}
>
Go to Details
</a>
React Native Navigator에서는 2번째 방법과 비슷하게 사용되지만
window.location을 전역을 사용하는 대신 화면 구성 요소에 전달되는 탐색 속성을 사용합니다.
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
// ... other code from the previous section
코드를 살펴보면 다음과 같습니다.
- navigation : 모든 Screen Component에 전달하는 역할을 수행합니다.
- navigate('Details') : 이동하려는 경로의 이름을 사용하여 navigate 함수에 전달합니다.
navigate에 전달되는 경로의 이름은 내비게이터에 정의된 경로로만 탐색할 수 있습니다.
만약 내비게이터에서 정의하지 않은 경로 이름으로 Navigation.navigate를 사용하면 개발 환경에서는 오류가 출력되고 프로덕션 환경에서는 아무 일도 일어나지 않습니다.
또한 navigate에 전달된 경로에 이미 위치해 있다면 아무 일도 일어나지 않습니다.
하지만 종종 데이터 변경으로 인해 화면을 새로 렌더링 할 필요가 있을 수 있습니다.
그때는 navigate의 .push()를 사용하면 기존 탐색 기록과 관계없이 다른 경로가 추가됩니다.
<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>
이전 화면으로 돌아가는 방법
native stack navigator의 헤더에는 기본적으로 뒤로 갈 수 있는 버튼이 제공됩니다.
navigation stack에 하나의 screen만 존재하는 상황에서는 뒤로 갈 수 있는 화면이 없기 때문에
이때는 뒤로 갈 수 있는 버튼이 표시되지 않습니다.
만약 따로 뒤로 가기 버튼을 만들고 싶다면 navigation.goBack()을 호출하여 동일한 동작을 구현할 수 있습니다.
function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
또 일반적으로 발생할 수 있는 요구 사항은 여러 화면으로 되돌아갈 수 있어야 한다는 점입니다.
예를 들어 스택에 여러 화면이 있고 모든 화면을 닫아 첫 번째 화면으로 돌아가려는 경우에
navigate('Home')을 사용할 수 있고 navigation.popToTop()을 사용할 수도 있습니다.
Routes 간에 파라미터를 넘기는 방법
각 화면 간에 params를 전달하려면 아래와 같은 2단계를 따릅니다.
1. navigation.navigate('RouteName', { /* 파라미터들 */ } 와 같이 사용하여 화면을 전환할 때 파라미터를 함께 전달합니다.
2. 전환된 화면에서 route.params에서 같이 넘어온 파라미터 데이터를 가져옵니다.
전달하는 매개변수는 JSON 직렬화 가능한 것이 좋습니다.
이렇게 하면 상태 지속성을 사용할 수 있으며 화면 구성 요소는 딥링크 구현을 위한 올바른 조건을 갖게 됩니다.
만약 화면을 전활 할 때 매개변수를 전달하지 않았을 때 기본 값을 설정하고 싶다면 initialParams를 사용할 수 있습니다.
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
만약 파라미터로 전달된 데이터가 변경되었고 이로 인해 state를 업데이트를 해야 하는 상황이라면
navigation.setParams를 사용할 수 있습니다.
navigation.setParams({
query: 'someText',
});
이전 화면으로 파라미터를 전달하기
매개변수는 일부 데이터를 새 화면에 전달하는 데 유용할 뿐만 아니라 이전 화면에 데이터를 전달하는 데에도 유용할 수 있습니다.
예를 들어, 게시물 작성 버튼이 있는 화면이 있고 게시물 작성 버튼을 누르면 게시물을 작성할 수 있는 새 화면이 열린다고 가정해 보겠습니다.
게시물을 작성한 후 게시물의 데이터를 이전 화면으로 다시 전달하고 싶은 상황입니다.
이를 만족하기 위해 화면이 이미 존재하는 경우 goBack처럼 작동하는 탐색 메서드를 사용할 수 있습니다.
function HomeScreen({ navigation, route }) {
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
}
}, [route.params?.post]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Create post"
onPress={() => navigation.navigate('CreatePost')}
/>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</View>
);
}
function CreatePostScreen({ navigation, route }) {
const [postText, setPostText] = React.useState('');
return (
<>
<TextInput
multiline
placeholder="What's on your mind?"
style={{ height: 200, padding: 10, backgroundColor: 'white' }}
value={postText}
onChangeText={setPostText}
/>
<Button
title="Done"
onPress={() => {
// Pass and merge params back to home screen
navigation.navigate({
name: 'Home',
params: { post: postText },
merge: true,
});
}}
/>
</>
);
}
중첩된 Navigator에서 파라미터 전달하기
만약 createNativeStackNavigator()로 여러 개의 스택을 만들었고 이 스택 간 파라미터를 전달하고 싶다면 조금 다르게 전달해야 합니다
navigation.navigate('Account', {
screen: 'Settings',
params: { user: 'jane' },
});
파라미터를 사용하는데 참고해야 할 사항
1. 화면에 필요한 데이터만 전달하기
파라미터는 필요한 데이터를 JSONSerializer 하게 전달하는 것이 좋습니다.
예를 들어, 사용자 ID가 필요한 경우 사용자 개체 전체를 파라미터로 전달하면 안 되고 사용자 ID만 전달해야 합니다.
또한 여러 화면에서 공통적으로 데이터가 사용될 경우 이는 파라미터로 전달하는 것보다 전역 저장소에 저장하는 것이 좋습니다.
2. 데이터 자체를 파라미터로 넘기지 않기
Navigate에 넘기는 경로 개체를 URL처럼 생각해 보겠습니다.
쇼핑 웹사이트에서 상품의 디테일 페이지에 접근할 때에는 파라미터로 상품의 id, 정렬 유형, 필터 등이 포함됩니다.
간혹 우리가 navigator를 사용하다 보면 아래와 같이 사용하고 싶을 수 있습니다.
// Don't do this
navigation.navigate('Profile', {
user: {
id: 'jane',
firstName: 'Jane',
lastName: 'Done',
age: 25,
},
});
이렇게 하면 추가 작업 없이 개체에 액세스 할 수 있어 편리해 보이지만 이는 안티 패턴입니다.
개체와 같은 데이터는 탐색 상태 대신 전역 저장소에 있어야 합니다.
그렇지 않으면 여러 위치에 동일한 데이터가 중복 선언되는 문제가 발생할 수 있습니다.
이로 인해 탐색 후 사용자 개체가 변경된 경우에도 프로필 화면에 오래된 데이터가 표시되는 등의 버그가 발생할 수 있습니다.
그리고 딥링킹이나 웹을 통해 화면에 연결하는 것도 다음과 같은 문제가 발생할 수 있습니다.
- URL은 화면을 표현하므로 매개변수, 즉 전체 사용자 개체도 포함해야 합니다. 이로 인해 URL이 매우 길어지고 읽을 수 없게 될 수 있습니다.
- 사용자 개체가 URL에 있으므로 존재하지 않거나 프로필에 잘못된 데이터가 있는 사용자를 나타내는 임의의 사용자 개체를 전달할 수 있습니다.
- 사용자 개체가 전달되지 않거나 형식이 부적절하면 화면이 이를 처리하는 방법을 알 수 없으므로 충돌이 발생할 수 있습니다.
이를 해결하는 좋은 예시는 사용자 ID만 전달해 API 등으로 추가 정보를 가져오는 방법입니다.
navigation.navigate('Profile', { userId: 'jane' });
'기술문서 읽기' 카테고리의 다른 글
ASGI에 대해서 (1) | 2024.02.08 |
---|---|
Rest API 디자인 모범 사례 (1) | 2024.01.28 |
데이터베이스 최적화하는 방법 11가지 (0) | 2024.01.14 |
Netflix에서 API를 탄력적으로 만드는 방법 (2) | 2023.12.31 |
대용량 데이터베이스에서 데이터를 효율적으로 Fetch 하는 방법 ( feat. Python Generator ) (0) | 2023.12.23 |