https://reactnative.directory/ 에서는 네이티브 기능(android, ios)들을 어떻게 쓸 수 있는지 소개하고 있다.
https://reactnative.dev/docs/components-and-apis#basic-components 에서는 리액트 네이티브의 컴포넌트에 대해 소개한다.
리액트 네이티브 프로젝트 구조
https://github.com/sophia22001/React-Native
GitHub - sophia22001/React-Native
Contribute to sophia22001/React-Native development by creating an account on GitHub.
github.com
리액트 네이티브 프로젝트를 생성했으면, React Native 앱의 진입점이 되는 `index.js` 를 보자.
index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
- `AppRegistry` : 앱의 루트 컴포넌트를 등록하는 모듈로, 어떤 컴포넌트를 렌더링할지를 담당한다.
- App 컴포넌트를 앱 이름에 등록하여 "MyApp"이라는 이름의 앱이 실행될 때 App 컴포넌트를 화면에 보여준다.
- 네이티브 코드(ios 또는 android)가 앱 이름을 기준으로 JS측의 루트 컴포넌트를 찾기 때문이다.
App.tsx
도 간단하게 바꿔줄 것이다.
기존 App.tsx 코드
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React from 'react';
import type {PropsWithChildren} from 'react';
import {
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
type SectionProps = PropsWithChildren<{
title: string;
}>;
function Section({children, title}: SectionProps): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: isDarkMode ? Colors.white : Colors.black,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: isDarkMode ? Colors.light : Colors.dark,
},
]}>
{children}
</Text>
</View>
);
}
function App(): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
/*
* To keep the template simple and small we're adding padding to prevent view
* from rendering under the System UI.
* For bigger apps the recommendation is to use `react-native-safe-area-context`:
* https://github.com/AppAndFlow/react-native-safe-area-context
*
* You can read more about it here:
* https://github.com/react-native-community/discussions-and-proposals/discussions/827
*/
const safePadding = '5%';
return (
<View style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={backgroundStyle.backgroundColor}
/>
<ScrollView style={backgroundStyle}>
<View style={{paddingRight: safePadding}}>
<Header />
</View>
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
paddingHorizontal: safePadding,
paddingBottom: safePadding,
}}>
<Section title="Step One">
Edit <Text style={styles.highlight}>App.tsx</Text> to change this
screen and then come back to see your edits.
</Section>
<Section title="See Your Changes">
<ReloadInstructions />
</Section>
<Section title="Debug">
<DebugInstructions />
</Section>
<Section title="Learn More">
Read the docs to discover what to do next:
</Section>
<LearnMoreLinks />
</View>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
});
export default App;
기본적인 코드
import React from 'react';
import {Text, View, StyleSheet} from 'react-native';
const App = () => {
return (
<View>
<Text>hello world</Text>
</View>
);
};
export default App;
이제부터 리액트 네이티브의 기본적인 컴포넌트와 작동을 알아보자.
View 와 Text
View와 Text는 모든 UI를 구성하는 가장 기본적인 빌딩 블록이다.
웹 개발에 비유하자면 View는 `div`와 같고, Text는 `p`나 `span`과 같다.
View 의 특징
UI 레이아웃을 위한 컨테이너 역할을 하는 컴포넌트이다.
다른 컴포넌트를 감싸고 그룹화하며, 스타일을 적용해 시각적인 요소를 만들 수 있다.
Text 의 특징
텍스트 내용을 표시하는 데 사용되는 컴포넌트이다.
텍스트를 표시하려면 반드시 Text 컴포넌트 안에 내용을 넣어야 하고, View 안에 직접 텍스트를 넣을 수 없다.
Style 적용하기
- 인라인 스타일
<View style={{width: "100%"}}></View>
- StyleSheet 스타일: 리액트에서 styled-components와 비슷한 느낌이다. `StyleSheet.create` 로 스타일들을 만든다.
import {Text, View, StyleSheet} from 'react-native';
const App = () => {
return (
<View style={styles.mainView}>
<View style={styles.subView}>
<Text style={styles.mainText}>hello world</Text>
</View>
<View style={styles.subView}>
<Text>hello world</Text>
</View>
<View style={styles.anotherSubView}>
<Text style={styles.mainText}>hello world</Text>
</View>
</View>
);
};
export default App;
const styles = StyleSheet.create({
mainView: {
flex: 1,
// ..
},
subView: {
flex: 1,
// ..
},
anotherSubView: {
flex: 2,
// ..
},
mainText: {
// ..
},
});
StyleSheet를 리액트 네이티브에서 import 하고,
아래에 따로 배열 형식의 스타일을 만든다. 여기서 스타일은 카멜케이스로 작성한다.
Flex: 1 ?
flex: 숫자 형식으로 작성하면 이는 화면을 차지하는 비율을 이야기하는 것이다.
첫번째 View와 두번째 View가 `flex: 1` 이고, 세번째 View는 `flex: 2`라면, 화면에서 1 : 1 : 2 의 비율을 차지하게 된다.
TouchEvent
https://reactnative.dev/docs/touchableOpacity
View는 touch에 반응한다.
View의 터치이벤트 : TouchableOpacity
View에서 터치 이벤트를 쓰려면 TouchableOpacity의 `onPress`라는 프롭스를 사용해 터치할 때의 이벤트를 나타낸다.
- `onPress` : 클릭하면 반응한다.
- `onLongPress` : 클릭을 오래하고 있어야 반응한다.
- `onPressIn` : 클릭한 뒤 바로 반응한다.
- `onPressOut` : 클릭하고 손을 땔 때 반응한다.
<TouchableOpacity onPress={() => Alert.alert('helloworld')}>
<View>
<Text>{props.name}</Text>
</View>
</TouchableOpacity>
- `TouchableWithoutFeedback` : `TouchableOpacity`는 클릭을 하는 순간 잠깐 투명하게 보이는데, 이건 클릭하는 순간에 투명하게 되지 않게 그대로 보여준다.
Text의 터치이벤트
Text에서는 다른 것 필요없이 바로 `onPress`를 적용하면 된다.
<View>
<Text onPress={() => Alert.alert('helloworld')}>Hello World</Text>
</View>
Button
https://reactnative.dev/docs/button
버튼은 필수적으로 `title` 프롭스를 갖으며, 이는 버튼의 이름이 된다.
<View>
<Button title="Add Number" />
</View>
아래 사진처럼 같은 코드인데 ios와 android인지에 따라 기본 버튼 스타일이 다르다.
Button에서 터치이벤트
이것도 마찬가지로 `onPress`로 바로 적용하면 된다.
<Button title="Add Number" onPress={() => add()} />
ScrollView
https://reactnative.dev/docs/scrollview
화면에 내용이 많아지면 아래로 스크롤 할 수 있도록 만들 수 있다.
- `onMomentumScrollBegin` : 스크롤이 움직이기 시작했을 때 트리거
- `onMomentumScrollEnd` : 스크롤의 움직임이 멈췄을 때(즉, 모두 내리거나 모두 올렸을 때) 트리거
- `onScroll` : 스크롤에 움직임이 발생했을 때(조금이라도 움직였으면) 트리거
- `onContentSizeChange(width, height)` : 스크롤 사이즈가 바뀌면 트리거
- `bounces` : 스크롤이 끝나면 통통 튀는 효과를 트리거. 기본값은 `true`이다.
<ScrollView style={{width: '100%'}} onScroll={() => Alert.alert('Scrolling')}>
<NumList num={state.random} onDelete={onNumDelete} />
</ScrollView>
TextInput
https://reactnative.dev/docs/textinput
앱 화면에서 키보드로 텍스트 값을 입력할 수 있다.
- `onChangeText` : 입력 값을 받아서 어떤 동작을 수행할 수 있게 해주는 함수
- `multiline` : `true`이면 입력값이 화면보다 늘어나면 자연스럽게 밑으로 확장시켜준다.(개행)
- `maxLength` : 입력 글자 수 제한
- `autoCapitalize` : `none` 이면 첫글자가 대문자로 나오지 못하게 한다.
- `editable` : `false` 이면 입력이 불가능해진다.
<TextInput
value={state.myTextInput}
onChangeText={onChangeInput}
multiline={true}
/>
Picker
https://github.com/react-native-picker/picker 을 참고해서 picker을 설치해준다.
여러가지 옵셥 선택지가 있고 그중 원하는 값을 고를 수 있는 것이다.
설치하기
npm install @react-native-picker/picker --save
ios는 pod 설치도 해줘야한다.
cd ios
pod install
Picker 사용하기
- `onSelectedValue` : 현재 선택된 값 보여주기
- `onValueChange` : 선택하면 그 `value` 가 적용되게 하기
import {Picker} from '@react-native-picker/picker';
// ..
<Picker
selectedValue={country}
onValueChange={(val, index) => setCountry(val)}>
<Picker.Item label="Korea" value="korea" />
<Picker.Item label="Canada" value="canada" />
<Picker.Item label="Canada2" value="canada2" />
</Picker>
안드로이드에서는 잘 되는데 ios에서 글씨가 안보이는 문제는 찾아봐도 너무 해결이 안되서 일단 냅두기로 했다.. ㅜㅜ
근데 요즘은 `react-native-picker-select`가 UI 를 바꾸기 쉬워서 더 잘 쓰이는 것 같다. https://github.com/lawnstarter/react-native-picker-select
Slider
https://github.com/callstack/react-native-slider 를 보고 설치해준다.
설치하기
npm install @react-native-community/slider --save
Slider 사용하기
- `minimumValue` : 최소 값
- `onValueChange` : 변경되는 Slider 값
- `minimumTrackTintColor` : 앞쪽 slider 선의 색
- `step`: 숫자 값
import Slider from '@react-native-community/slider';
// ...
<Slider
value={value}
minimumValue={0}
maximumValue={100}
onValueChange={val => setValue(val)}
maximumTrackTintColor="red"
minimumTrackTintColor="blue"
step={10}
/>
ActivityIndicator
화면을 전환하거나 다운로드를 받을 때, 서버에서 데이터를 받는 중일 때 로딩된다는 빙글빙글 표시를 만들 수 있다.
- `size` : 로딩 표시의 크기
- `color` : 로딩 표시의 색상
- `animating` : 이 프로퍼티가 true 여야 표시된다.
<ActivityIndicator
style={{paddingTop: 200}}
size="large"
color="green"
animating={true}
/>
Image
이미지를 화면에 띄울 수 있다.
- `source` : 표시할 이미지의 위치(URL 또는 로컬 파일 경로)를 지정한다.
- `resizeMode` : 이미지 원본의 크기가 Image 컴포넌트의 지정된 크기(style속성으로 설정한 `width`와 `height`)와 다를 때, 이미지를 어떻게 조정하여 표시할지 결정한다.
- `onLoadedEnd` : 이미지 로딩이 끝나면 동작을 트리거
1. 로컬에서 이미지 가져오기
import Train from './assets/images/train.jpg';
<Image
source={Train}
resizeMode="contain"
onLoadEnd={() => Alert.alert('Image Loaded!!')}
/>
resizeMode
Cover과 Contain의 차이
- `Cover` : Image 컴포넌트 영역에 이미지를 다 채운다. (기본값) 그래서 어쩔 수 없이 잘리는 부분이 생긴다.
- `Contain` : Image 컴포넌트 영역 안에 완전히 들어오도록 원본 이미지 전체를 보여준다.
2. 서버에서 이미지 가져오기
서버: https://picsum.photos/ - 사진을 가져올 수 있는 웹주소 제공한다.
위 사이트에서 알려주는 주소로 사용해보자. source 에서 `uri`로 주소를 지정해주면 된다.
<Image
source={{uri: 'https://picsum.photos/id/237/200/300'}}
resizeMode="contain"
/>
여기서 헷갈릴 수도 있는게 웹사이트에서 사진보다 잘린 것처럼 보이지만,
이미지 주소 url을 보면 `../200/300`으로 되어있는데 이는 `width`와 `height`를 말한다. 즉, 원본이 200, 300 사이즈로 잘려있는 것이다.
Modal
화면 가장 위에 표시될 레이어이다. ex> 광고 띄우기, 경고창 띄우기
Modal은 독립적인 렌더링 계층을 갖으며, 부모 View의 자식으로 존재하지만, 실제로는 화면의 최상단에 띄워지는 팝업과 같은 역할을 하는 것이다.
- `visible` : `true`로 설정되면 Modal 내용이 보이게 된다.
- `animationType` : 어떤 방식으로 모달이 띄워질지를 결정한다. `slide`, `fade` 방식이 있으며 기본값은 `none`이다.
- `onShow` : 모달이 띄워졌을 때 트리거된다.
<View>
<Button title="Open Modal" onPress={handleModal} />
<Modal
visible={modal}
animationType="slide"
onShow={() => Alert.alert('Warning@')}>
<View style={{marginTop: 60, backgroundColor: 'red'}}>
<Text>This is modal content</Text>
</View>
<Button title="Go Back" onPress={handleModal} />
</Modal>
</View>
버튼을 누르면 모달로 넘어가는데 여기서 버튼은 사라진 것 처럼 보인다.
버튼 컴포넌트가 사라지는 것이 아니라, Modal 컴포넌트가 화면 전체를 덮어버려서 기존에 있던 Button 컴포넌트가 가려지는 것이다.
'[App] React Native > Study' 카테고리의 다른 글
React Navigation (3) - Tab (1) | 2025.06.20 |
---|---|
React Navigation (2) - Drawer (0) | 2025.06.20 |
React Navigation (1) - Stack (3) | 2025.06.19 |
ios & Android Simulator 구동하기 (5) | 2025.05.21 |
React Native 소개 및 개발 환경 구축 (1) | 2025.05.21 |