Ch 03. React Native 학습 시 주요 개념
1. Core Components
Android와 iOS의 UI 컴포넌트 구조 차이가 있지만
React Native는 같은 JSX 코드를 사용해도 Android와 iOS에서 각각 네이티브 UI 컴포넌트로 변환됨.
- Android에서는 내부적으로 ViewGroup > ImageView + TextView 로 변환.
- iOS에서는 내부적으로 UIView > UIImageView + UITextView 로 변환.
한 번의 코드 작성으로 Android & iOS 모두 대응 가능!
React Native의 코어 컴포넌트(Core Components)란?
React Native에서 기본적으로 제공되는 UI 요소를 의미한다.
React에서
, , 같은 웹 요소를 사용하듯이,
React Native에서는 모바일 앱에 맞는 네이티브 컴포넌트를 제공한다.
주요 코어 컴포넌트 정리
컴포넌트 | 설명 | 비고 |
---|---|---|
View | div와 비슷한 컨테이너 역할 | 레이아웃 잡을 때 필수 |
Text | 텍스트를 렌더링하는 컴포넌트 | div 안에처럼 써야 함 |
Image | 이미지를 표시하는 컴포넌트 | source={{ uri: "url" }} 형태 |
ScrollView | 스크롤 가능한 화면 | flex: 1 설정 자주 필요 |
FlatList | 성능 최적화된 리스트 렌더링 | 대량 데이터 표시 시 사용 |
TouchableOpacity | 터치 가능한 버튼 역할 | 터치 시 투명도 조절 효과 |
TextInput | 사용자가 입력할 수 있는 필드 | onChangeText로 값 업데이트 |
Button | 기본 버튼 제공 | 커스터마이징 어려움 |
SafeAreaView | 노치 있는 디바이스에서 안전한 영역 | iPhoneX 이후 필수 |
button은 다르게 만들어서 쓴다.
추후 설명..
2. 컴포넌트와 prop
1. 컴포넌트(Component)란?
재사용 가능한 개별적인 UI 조각
- React Native에서 UI를 구성하는 기본 단위
- 여러 개의 컴포넌트를 조합하여 화면을 구성
- 유지보수와 재사용성을 높일 수 있음
2. Prop(속성)이란?
부모 → 자식 컴포넌트로 데이터를 전달하는 방법
- 부모 컴포넌트에서 자식 컴포넌트로 값을 내려주는 역할
- 자식 컴포넌트에서는 부모로부터 받은 prop을 직접 수정할 수 없음(불변성)
props.name은 부모에서 넘겨준 값이라 자식에서 변경 불가!
만약 변경하고 싶다면 부모에서 상태(state)로 관리해야 함
3. 컴포넌트의 종류
1) 클래스형 컴포넌트 (Class Component)
- 예전 방식, 현재는 거의 사용 안 함
- state와 생명주기 메서드(componentDidMount 등)을 가짐
- React Native에서 React.Component를 상속받아 사용
- class 키워드 필요
- render() 메서드 반드시 필요
- 함수형보다 메모리 자원을 더 사용한다
import React, { Component } from "react";
import { Text, View } from "react-native";
class MyClassComponent extends Component {
render() {
return (
<View>
<Text>Hello, {this.props.name}!</Text>
</View>
);
}
}
2) 함수형 컴포넌트 (Function Component)
- 현재 React Native에서 주로 사용되는 방식!
- state, lifeCycle관련 기능 사용 불가능 useState, useEffect 같은 훅(Hook)과 함께 사용 가능
const MyFunctionComponent = ({ name }) => {
return (
<View>
<Text>Hello, {name}!</Text>
</View>
);
};
📌 현재는 함수형 컴포넌트 + 훅(Hooks) 조합이 표준!
3. 컴포넌트와 prop : 실습
코드보기 👇🏻👇🏻👇
import React from 'react';
import { Image, StyleSheet, Text, View } from "react-native";
const Header = (props: any) => <Text>{props.title}</Text>;
const MyProfile = () => (
<Text>
<Profile
uri="https://i.namu.wiki/i/pKp6bM6ovVkqzTlwj5lkWjCfyLCITAU3bP5chwJc7TcsgEh9dJxNGbAUfnTTlFsjAzmIG586bMk56Oa5OgHEZw.webp"
name="카리나"
profileSize={64}
/>
</Text>
);
const Profile = (props: any) => {
return (
<View style={{ flexDirection: "row" }}>
<Image
source={{
uri: props.uri
}}
style={{
width: props.profileSize,
height: props.profileSize,
}}
/>
<Text>{props.name}</Text>
</View>
);
}
const Division = () => <Text>Division</Text>;
const FriendSection = () => (
<Text></Text>
);
const FriendList = () => {
return (
<View>
<Profile
uri="https://i.namu.wiki/i/pKp6bM6ovVkqzTlwj5lkWjCfyLCITAU3bP5chwJc7TcsgEh9dJxNGbAUfnTTlFsjAzmIG586bMk56Oa5OgHEZw.webp"
name="카리나"
profileSize={50}
/>
<Profile
uri="https://i.namu.wiki/i/pKp6bM6ovVkqzTlwj5lkWjCfyLCITAU3bP5chwJc7TcsgEh9dJxNGbAUfnTTlFsjAzmIG586bMk56Oa5OgHEZw.webp"
name="카리나"
profileSize={50}
/>
<Profile
uri="https://i.namu.wiki/i/pKp6bM6ovVkqzTlwj5lkWjCfyLCITAU3bP5chwJc7TcsgEh9dJxNGbAUfnTTlFsjAzmIG586bMk56Oa5OgHEZw.webp"
name="카리나"
profileSize={50}
/>
<Profile
uri="https://i.namu.wiki/i/pKp6bM6ovVkqzTlwj5lkWjCfyLCITAU3bP5chwJc7TcsgEh9dJxNGbAUfnTTlFsjAzmIG586bMk56Oa5OgHEZw.webp"
name="카리나"
profileSize={50}
/>
</View>
);
}
export default function HomeScreen() {
return (
<View>
<Header title="친구"/>
<MyProfile />
<Division />
<FriendSection />
<FriendList />
</View>
);
}
const styles = StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
reactLogo: {
height: 178,
width: 290,
bottom: 0,
left: 0,
position: 'absolute',
},
});
ios 시뮬레이터 써보고싶어서 설정하느라 시간 다 갔음
https://disco-biscuit.tistory.com/151
리액트 좀 써봐서 비슷한데 다른부분이 많다.
TML요소랑 코어컴포넌트가 대응되는게 있어서 정리해봤다.
컴포넌트 | 설명 | 비고 |
View | div와 비슷한 컨테이너 역할 | 레이아웃 잡을 때 필수 |
Text | 텍스트를 렌더링하는 컴포넌트 | div 안에 <p>처럼 써야 함 |
Image | 이미지를 표시하는 컴포넌트 | source={{ uri: "url" }} 형태 |
ScrollView | 스크롤 가능한 화면 | flex: 1 설정 자주 필요 |
FlatList | 성능 최적화된 리스트 렌더링 | 대량 데이터 표시 시 사용 |
TouchableOpacity | 터치 가능한 버튼 역할 | 터치 시 투명도 조절 효과 |
TextInput | 사용자가 입력할 수 있는 필드 | onChangeText로 값 업데이트 |
Button | 기본 버튼 제공 | 커스터마이징 어려움 |
SafeAreaView | 노치 있는 디바이스에서 안전한 영역 | iPhoneX 이후 필수 |
4. React Hooks (1) useState 이론&실습
클래스형컴포넌트에서 state
import React from "react";
import { Button, Text, View } from "react-native";
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
render() {
return (
<View>
<Text>You clicked {this.state.count} times</Text>
<Button
title="Click me"
onPress={() => this.setState({ count: this.state.count + 1 })}
/>
</View>
);
}
}
export default Component;
함수형컴포넌트에서 state(useState)
import React, { useState } from "react";
import { Button, Text, View } from "react-native";
const Component = () => {
const [count, setCount] = useState(0);
return (
<View>
<Text>You clicked {count} times</Text>
<Button title="Click me" onPress={() => setCount(count + 1)} />
</View>
);
};
export default Component;
클래스형컴포넌트보다 함수형 컴포넌트로 쓰는것이 더 짧고 가독성이 좋음.
5. React Hooks (2) useEffect 이론_실습
// didmount
useEffect(() => {...}, [])
// didupate
useEffect(() => {...}, [state])
// willunmount
useEffect(() => {
return () => {
// 언마운트될때 실행될 코드
};
}, []);
useEffect로 didMount와 didUpdate, willUnmount를 대체할수있음
6. React Hooks (3) custom 이론_실습
인풋에서 값을 받아 state에 저장하고 초기화할수있는 컴포넌트이다.
똑같은게 3개라서 코드중복이 있다.
customHook.js
import React, { useState } from "react";
import { Button, StyleSheet, TextInput, View } from "react-native";
const InputBox = (props) => {
return (
<View style={styles.flex}>
<TextInput
value={props.value}
onChangeText={props.onChangeText}
placeholder={props.placeholder}
style={styles.input}
/>
<Button title="초기화" onPress={props.onReset} />
</View>
);
};
const CustomHook = () => {
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const [city, setCity] = useState("");
return (
<View style={styles.container}>
<InputBox
value={name}
onChangeText={setName}
placeholder="이름을 입력하세요"
onReset={() => setName("")}
/>
<InputBox
value={age}
onChangeText={setAge}
placeholder="나이를 입력하세요"
onReset={() => setAge("")}
/>
<InputBox
value={city}
onChangeText={setCity}
placeholder="도시을 입력하세요"
onReset={() => setCity("")}
/>
</View>
);
};
export default CustomHook;
UI부분에서 InputBox로 반복되는 컴포넌트를 따로 빼서 재사용가능한 컴포넌트로 빼주었지만
onChangeText나 onReset등 코드가 여전히 반복됨 -> 커스텀훅이 필요하다.
// custom hook
const useInput = (initialValue) => {
const [value, setValue] = useState(initialValue);
const resetValue = () => setValue(initialValue);
return {
value,
setValue,
resetValue,
};
};
커스텀훅 안에서 useState로 생성할거임
useState부분을 커스텀훅사용하기위해 변경하기
const CustomHook = () => {
// const [name, setName] = useState("");
const output = useInput("");
const name = output.value;
const setName = output.setValue;
const resetName = output.resetValue;
...
이렇게 작성하면 길기때문에
const CustomHook = () => {
// refactored 구조분해할당
const {
value: name,
setValue: setName,
resetValue: resetName,
} = useInput("");
한줄로 커스텀훅 사용
그리고 onReset에서onReset={() => setCity("")}
을 onReset={resetCity}
로 사용하여
명시적인 초기화 함수를 전달한다.
커스텀훅사용 최종코드
import React, { useState } from "react";
import { Button, StyleSheet, TextInput, View } from "react-native";
const InputBox = (props) => {
return (
<View style={styles.flex}>
<TextInput
value={props.value}
onChangeText={props.onChangeText}
placeholder={props.placeholder}
style={styles.input}
/>
<Button title="초기화" onPress={props.onReset} />
</View>
);
};
// custom hook
const useInput = (initialValue) => {
const [value, setValue] = useState(initialValue);
const resetValue = () => setValue(initialValue);
return {
value,
setValue,
resetValue,
};
};
const CustomHook = () => {
const {
value: name,
setValue: setName,
resetValue: resetName,
} = useInput("");
const {
value: city,
setValue: setCity,
resetValue: resetCity,
} = useInput("");
const {
value: age,
setValue: setAge,
resetValue: resetAge,
} = useInput("");
// const [age, setAge] = useState(0);
// const [city, setCity] = useState("");
return (
<View style={styles.container}>
<InputBox
value={name}
onChangeText={setName}
placeholder="이름을 입력하세요"
onReset={resetName}
/>
<InputBox
value={age}
onChangeText={setAge}
placeholder="나이를 입력하세요"
onReset={resetAge}
/>
<InputBox
value={city}
onChangeText={setCity}
placeholder="도시을 입력하세요"
onReset={resetCity}
/>
</View>
);
};
export default CustomHook;
'Frontend > React Native' 카테고리의 다른 글
React Native 2-1. 카카오톡 친구목록 클론코딩(3): expo 기본앱에서 tabbar 커스텀 하기 (0) | 2025.03.13 |
---|---|
React Native 2-1. 카카오톡 친구목록 클론코딩(2) (0) | 2025.03.10 |
React Native 2-1. 카카오톡 친구목록 클론코딩(1) (0) | 2025.03.10 |
React Native Expo실행시 iOS Simulator 실행안됨 해결 (0) | 2025.03.06 |
React Native 1. 소개 및 Expo 세팅 (0) | 2025.02.19 |