React-native 를 공부하면서 배웠던 지식들을 정리해 보았습니다.
실행할 때 npm start -> npm run ios 따로따로 터미널에서 실행해 주어야 합니다.
이유는 나중에 어플리케이션을 re-build 할 때 npm start 해준 터미널에서 r 만 눌러줘도 re - build 가 됩니다.
splash-screen
애플리케이션이나 웹사이트가 로드될 때 사용자에게 일시적으로 표시되는 화면을 말합니다.
일반적으로 앱이나 웹사이트가 완전히 로드되기 전에 나타나며, 사용자가 로딩 시간을 덜 느끼게 하고,
동시에 브랜드 이미지나 로고를 효과적으로 노출할 수 있는 기회를 제공합니다.
스플래시 화면
모바일 앱이나 웹 애플리케이션이 시작될 때 앱이 로딩되는 동안 사용자에게 보이는 화면입니다.
주로 앱의 로고, 애플리케이션의 이름, 혹은 로딩 상태를 간단하게 나타내는 그래픽이 등장합니다.
설치
expo install expo-splash-screen
npx pod-install ios
기본 사용법
import { useCallback, useEffect, useState } from "react"
import * as SplashScreen from 'expo-splash-screen';
import { Text, View } from "react-native";
SplashScreen.preventAutoHideAsync(); // <-- 자동 사라지기 방지
export default function App() {
const [ready, setReady] = useState(false);
useEffect(() => {
const prepare = async () => {
try {
// 사전에 font , image 를 불러오는 작업을 할 때...
} catch(e) {
console.warn(e)
} finally {
setReady(true);
}
}
prepare();
}, [])
const onLayoutRootView = useCallback(async () => {
if (ready) await SplashScreen.hideAsync(); // <-- 의도적 사라지기
},[ready])
if(!ready) {
return null;
}
return (
<View onLayout={onLayoutRootView}>
<Text>Hello</Text>
</View>
)
}
코드에서 주의깊게 볼 부분은 SplashScreen.preventAutoHideAsync(), SplashScreen.hideAsync() 입니다.
SplashScreen.preventAutoHideAsync()
preventAutoHideAsync 함수는 스플래시 화면이 자동으로 사라지는 것을 막는 기능입니다.
스플래시 화면이 자동으로 사라지는 경우는 어떤 것이 있을까요??
1. 시간초과
대부분의 앱 플랫폼에서는 스플래시 화면을 일정 시간이 지난 후 자동으로 숨기는 기능을 내장하고 있습니다.
이는 앱이 시작될 때 일정 시간이 지나면 자동으로 메인 화면으로 전환되도록 만들어주는 것입니다.
2. 사용자 상호 작용
사용자가 스플래시 화면을 터치하거나 다른 상호 작용을 시작할 때,
일부 앱은 이를 감지하고 스플래시 화면을 숨기고 메인 화면으로 전환합니다.
사용자 상호 작용은 앱의 로딩이 완료되었을 때, 예상치 못한 동작을 일으키는 경우가 있습니다.
SplashScreen.hideAsync()
hideAsync 함수는 스플래시 화면을 숨기는 역할을 합니다.
즉 내가 원하는 동작이 끝난 뒤 의도적으로 스플래시 화면을 숨길 수 있도록 도와주는 함수죠.
expo-font, expo-asset
expo-font
앱에서 사용할 폰트를 로드하고 관리하는 데 사용합니다. ( https://icons.expo.fyi/Index )
엄청 다양한 icons 들을 가져와 사용할 수 있게 만들어 줍니다.
expo-asset
이미지, 비디오, 사운드 등 다양한 미디어 자산을 관리하는 데 사용됩니다.
설치
expo install expo-font
expo install expo-asset
npx pod-install ios
기본 사용법
import { useCallback, useEffect, useState } from "react"
import * as SplashScreen from 'expo-splash-screen';
import * as Font from 'expo-font';
import { Text, View } from "react-native";
import {Ionicons} from "@expo/vector-icons";
import { Asset } from "expo-asset";
SplashScreen.preventAutoHideAsync();
export default function App() {
const [ready, setReady] = useState(false);
useEffect(() => {
const prepare = async () => {
try {
await Font.loadAsync(Ionicons.font) // <----
await Asset.loadAsync(require('./testImg.jpeg')); // <----
} catch(e) {
console.warn(e)
} finally {
setReady(true);
}
}
prepare();
}, [])
//.....
위에 코드에서 font, asset 은 둘 다 loadAsync 함수를 사용하고 있습니다. loadAsync 함수는 비동기적으로 자산을 로드하고 캐시 할 수 있습니다. 기본적으로 SplashScreen 과 같이 사용됩니다.
react-native 에서 icons 를 사용하는 방법입니다. ( https://icons.expo.fyi/Index )
@expo/vector-icons directory
icons.expo.fyi
useAssets, Font.useFonts
useAssets
위에서 배웠던 expo-asset 과 같은 동작을 수행합니다. 하지만 차이점은 여러 개의 자산을 묶어서 로드하고 캐시 할 때 사용됩니다.
Font.useFonts
위에서 배웠던 expo-font 와 같은 동작을 수행하지만 useAssets 와 마찬가지로 여러 개의 폰트를 로드하고 캐시 합니다.
import { useCallback } from "react"
import { Text, View } from "react-native";
import * as SplashScreen from 'expo-splash-screen';
import * as Font from 'expo-font';
import { useAssets } from "expo-asset";
import {Ionicons} from "@expo/vector-icons";
SplashScreen.preventAutoHideAsync();
export default function App() {
const [assets] = useAssets([require('./testImg.jpeg')]) // <---
const [fonts] = Font.useFonts(Ionicons.font) // <---
const onLayoutRootView = useCallback(async () => {
if (assets && fonts) await SplashScreen.hideAsync();
},[assets, fonts])
if(!assets && !fonts) {
return null;
}
return (
<View onLayout={onLayoutRootView}>
<Text>hello</Text>
<Ionicons name="accessibility-outline" size={24} color="black" />
<Ionicons name="alarm-sharp" size={24} color="black" />
</View>
)
}
useAssets, useFonts 함수를 사용하면 여러 개의 자산을 로드할 수 있습니다.
리스트 변수에 들어가는 값은 boolean 값입니다. 즉 true 가 반환되면 자산이 로드됐다는 뜻이고 이 값을 이용해서 SplashScreen
에 적용하여 모두 로드했다고 알려주고 hideAsync 함수로 스플래시 화면을 종료할 수도 있습니다.
Navigation
React-native 에서 navigation 을 엄청 손쉽게 만들어주는 라이브러리입니다. ( https://reactnavigation.org/ )
React Navigation | React Navigation
Routing and navigation for your React Native apps
reactnavigation.org
설치
npm install @react-navigation/native
expo install react-native-screens react-native-safe-area-context
npx pod-install ios (macOS 환경에서 ios 를 개발하고 있다면 설치)
이 상태에서 더 추가해야 하는 코드들도 있지만 react-native-app 으로 설치한 폴더라면 자동으로 설정되어 있기 때문에 신경 쓰지 않아도 됩니다.
bottom-tabs
하단 bottom Navigation 을 만드는 방법입니다.
설치
npm install @react-navigation/bottom-tabs
import { useCallback } from "react"
import * as SplashScreen from 'expo-splash-screen';
import * as Font from 'expo-font';
import { useAssets } from "expo-asset";
import {Ionicons} from "@expo/vector-icons";
import { NavigationContainer } from '@react-navigation/native';
import Tabs from './navigation/Tabs';
SplashScreen.preventAutoHideAsync();
export default function App() {
const [assets] = useAssets([require('./testImg.jpeg')])
const [fonts] = Font.useFonts(Ionicons.font)
const onLayoutRootView = useCallback(async () => {
if (assets && fonts) await SplashScreen.hideAsync();
},[assets, fonts])
if(!assets || !fonts) {
return null;
}
return (
<NavigationContainer onReady={onLayoutRootView}>
<Tabs/>
</NavigationContainer>
)
}
<-- 이렇게 나오면 다행이라고 생각합니다.
하지만 대부분 처음 빌드를 하시면
Invariant Violation: requireNativeComponent: "RNSScreen" was not found in the UIManager.....
라는 오류를 볼 수 있으실 것입니다. 이때 앱을 re-build 하셔야 합니다.
[앱 re-build 과정 요약]
1. 터미널, 에뮬레이터 모두 종료 후 재시작
2. React Navigation 공홈 들어가서 https://reactnavigation.org/docs/getting-started 시키는 대로 순서대로 다시 한번 패키지 인스톨 (안 해도 될 수도)
3. `npm start` 로 실행시키면 re-build 과정이 일어나지 않습니다.
4. 'npm run ios' 명령어 실행
5. 에뮬레이터를 실행하면 프로그램이 정상 작동되는 것을 확인하실 수 있으실 겁니다
깨알 꿀팁
<Tap.Navigator initialRouteName="Tv">
앱이 처음 실행될 때 어떤 navbar 내용을 보여줄지 정해줍니다.
즉 Tv 부분을 먼저 보여준다고 생각하시면 됩니다.
그리고 다양한 options 를 지원해 주기 때문에 하단에 링크를 타고 들어가면 다양한 options 를 확인하실 수 있습니다.
https://reactnavigation.org/docs/bottom-tab-navigator/#tabbarbadgestyle
Bottom Tabs Navigator | React Navigation
A simple tab bar on the bottom of the screen that lets you switch between different routes. Routes are lazily initialized -- their screen components are not mounted until they are first focused.
reactnavigation.org
useColorScheme
앱에서 다크모드, 라이트모드에 따라 동적으로 변하는 값을 지원해 줍니다.
import { useColorScheme } from "react-native";
const Tabs = () => {
const colorScheme = useColorScheme();
console.log(colorScheme);
//....
return (
//....
console.log() 로 찍어본 결과 라이트모드일 때 light , 다크모드일 때 dark 라고 출력이 됩니다.
DarkTheme, DefaultTheme
useColorScheme 함수와 같이 이용되는 함수로써 자동적으로 스타일을 지원해 주는 함수들입니다.
DarkTheme 는 다크 모드의 스타일을 자동적으로 지원해 주며, DefaultTheme 는 라이트 모드의 스타일을 자동적으로 지원해 줍니다.
import { NavigationContainer, DarkTheme, DefaultTheme } from '@react-navigation/native';
export default function App() {
const isDark = useColorScheme() === "dark";
// ...생략
return (
<NavigationContainer theme={isDark ? DarkTheme : DefaultTheme} onReady={onLayoutRootView}>
<Tabs/>
//... 생략
Stack navigator
Stack Navigator는 화면들을 스택(stack) 구조로 쌓아 올려서,
사용자가 화면을 이동할 때 새로운 화면이 현재 화면 위에 쌓이는 방식으로 동작합니다.
react-navigation 라이브러리를 살펴보면 Stack, native stack 두 가지의 stack navigation 을 볼 수 있습니다.
Stack 은 js 로 구성되어 있기 때문에 ios, android 에서 제공하는 navigater 보다 성능면에서 안 좋을 수 있습니다.
하지만 Native Stack 은 ios 에서 제공하는 UINavigationController 이나 android 에서 제공하는 Fragment 를 이용하여 구현했기 때문에 성능면에서 우수합니다.
따라서 native stack 을 설치하고 사용하는 것이 성능면, 기능에서 우수하기 때문에 추천합니다!!
설치
npm install @react-navigation/native-stack
navigation/Stack.js 파일에 만들어줍니다.
import React from "react";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { Text } from "react-native";
const ScreenOne = () => (<Text>go to One</Text>);
const ScreenTwo = () => (<Text>go to two</Text>);
const ScreenThree = () => (<Text>go to three</Text>);
const NativeStack = createNativeStackNavigator();
const Stack = () => (
<NativeStack.Navigator>
<NativeStack.Screen name="One" component={ScreenOne} />
<NativeStack.Screen name="Two" component={ScreenTwo} />
<NativeStack.Screen name="Three" component={ScreenThree} />
</NativeStack.Navigator>
);
export default Stack;
마지막으로 App 파일에 NavigationContainer 컴포넌트 안에 넣어주면 됩니다.
import { NavigationContainer, DarkTheme, DefaultTheme } from '@react-navigation/native';
import Stack from './navigation/Stack';
export default function App() {
const isDark = useColorScheme() === "dark";
// ...생략
return (
<NavigationContainer theme={isDark ? DarkTheme : DefaultTheme} onReady={onLayoutRootView}>
<Stack/>
//... 생략
하지만 이렇게만 하면 제대로 된 Stack navigation 기능을 사용할 수 없습니다.
stack 처럼 타고 타고 이동해야 하기 때문이죠.
navigate, goBack 이라는 Options 를 사용하면 원하는 Stack navigation 기능을 사용할 수 있습니다.
navigate, goBack
navigate 는 특정 파일로 이동하고 싶을 때 사용합니다.
goBack 은 특정 파일로 이동하기 전 상태로 돌아갑니다.
import React from "react";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { Text, View, TouchableOpacity } from "react-native";
const ScreenOne = ({ navigation: { navigate } }) => (
<TouchableOpacity onPress={() => navigate("Two")}>
<Text>go to two</Text>
</TouchableOpacity>
);
const ScreenTwo = ({ navigation: { navigate } }) => (
<TouchableOpacity onPress={() => navigate("Three")}>
<Text>go to three</Text>
</TouchableOpacity>
);
const ScreenThree = ({ navigation: { goBack } }) => (
<TouchableOpacity onPress={() => goBack()}>
<Text>Change title</Text>
</TouchableOpacity>
);
const NativeStack = createNativeStackNavigator();
const Stack = () => (
<NativeStack.Navigator>
<NativeStack.Screen name="One" component={ScreenOne} />
<NativeStack.Screen name="Two" component={ScreenTwo} />
<NativeStack.Screen name="Three" component={ScreenThree} />
</NativeStack.Navigator>
);
export default Stack;
ScreenOne 이라는 컴포넌트를 보고 있을 때 Text 를 클릭하면 NativeStack.Screen name =" " 에서 정의한 name 에 따라 이동시켜 줍니다. 해당 페이지로 이동하는 것이죠. 그러한 기능을 navigate("Two") 라는 옵션이 도와줍니다.
중요한 점은 NativeStack 을 사용하는 개발자라면 options 을 사용하고 싶을 때 모든 부분은 navigation props 에서 나오는 것을 생각해야 한다는 것입니다. { navigation: { navigate } } 같은 경우를 말합니다.
Stack , Tabs 합치기
앞에서 배웠던 stack, tabs 를 같이 쓰고 싶다면 어떻게 해야 할까요??
stack 기능과 tab 기능을 같이 쓰고 싶다면 Root navigater 을 설정해서 사용하면 됩니다.
그림에서 설명한 것처럼 똑같이 따라 하시면 Stack, Tabs 를 같이 사용할 수 있습니다.
하지만 여기서 하나 더 설정해야 하는 부분이 있습니다. Stack Navigator 즉 stack 을 어디서 사용해야 하는지입니다.
제가 bottom tabs 로 설정한 부분은 Home, Tv, Search 부분이며
Home 에서 Stack 기능을 사용하고 싶다면 코드를 바꾸어 주어야 합니다.
// Movies.js
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
const Movie = ({navigation: {navigate}}) => (
<TouchableOpacity
onPress={() => navigate("Stack", {screen: "One"})}
>
<Text>Movie</Text>
</TouchableOpacity>
)
export default Movie;
Movie Component 를 위에 코드처럼 설정을 한다면 위에서 설정한 ScreenOne Component 로 이동할 수 있습니다.
여기서 가장 중요한 부분은 navigate("", {screen: ""}) 입니다.
Navigater 에서 다른 Navigater 로 이동하고 싶을 때 사용합니다.
제가 설정한 Stack, tabs 처럼 두 개 이상의 navigater 를 쓰고 있을 때를 말합니다.
여기서 navigate("", {screen: ""}) 문법은 어디로 가는지 방향을 알려주는 방법입니다.
예를 들어 화장실로 가려면 편의점으로 들어가서 오른쪽으로 걸어가면 있어 라는 말과 똑같습니다.
styled-components
react-native 에서 스타일링해주는 도구 중 styled-components 를 사용하고 있으며 이 부분에 대해 설명하겠습니다.
import React from 'react';
import styled from 'styled-components/native';
const Movie = ({navigation: {navigate}}) => (
<Btn onPress={() => navigate("Stack", {screen: "One"})}>
<Title seleted={true}>Movie</Title>
</Btn>
)
const Btn = styled.TouchableOpacity`
flex: 1;
justify-content: center;
align-items: center;
`
const Title = styled.Text`
color: ${props => props.seleted ? "orange" : "black"};
`
export default Movie;
styled-components 의 장점은 항상 react-native 에서 View, Text 등을 꺼내오지 않아도 된다는 것입니다.
styled-components 만 불러와도 View, Text 등을 사용할 수 있습니다.
여기서 중요한 부분은 import styled from 'styled-components/native';
라고 불러올 때 /native 를 꼭 붙여줍시다!!
Theme
스타일을 전역적으로 사용하고 싶을 때 ThemeProvider 을 사용하면 된다.
여기서 엄청 중요한 부분은 ThemeProvider 을 불러올 때 자동 불러오기를 하면
import { ThemeProvider } from '@react-navigation/native' 로 나옵니다.
하지만 import { ThemeProvider } from 'styled-components/native'; 이걸로 해야 합니다.
//Styled.js
export const lightTheme = {
mainBgColor: "white",
textColor: "#1e272e",
};
export const darkTheme = {
mainBgColor: "#1e272e",
textColor: "#d2dae2",
};
//App.js
return (
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<NavigationContainer onReady={onLayoutRootView}>
<Root/>
</NavigationContainer>
</ThemeProvider>
);
//Movie.js
import React from 'react';
import styled from 'styled-components/native';
const Movie = ({navigation: {navigate}}) => (
<Btn onPress={() => navigate("Stack", {screen: "One"})}>
<Title seleted={true}>Movie</Title>
</Btn>
)
const Btn = styled.TouchableOpacity`
flex: 1;
justify-content: center;
align-items: center;
background-color: ${props => props.theme.mainBgColor}; <-- 사용
`
const Title = styled.Text`
color: ${props => props.theme.textColor}; <-- 사용
`
export default Movie;
FlatList - onEndReached , onEndReachedThreshold
onEndReached
FlatList 자식 요소들 에서 끝지점에 도달했을 때 함수를 실행하게 해줍니다.
onEndReachedThreshold
끝지점이 어디를 의미하는지 설정할 수 있게 해줍니다.
const loadMore = () => {
console.log("hello")
}
<FlatList
onEndReached={loadMore}
onEndReachedThreshold={0.4}
'React-native' 카테고리의 다른 글
React-native 에서 firebase 적용하기 (0) | 2024.06.21 |
---|---|
React-native - Animation (1) | 2024.06.13 |
React-native - 기술 (1) | 2024.05.26 |