목 차
📲 React Native 기본기 다지기
📍 2. 컴포넌트 기반 개발.
2-1. 컴포넌트 기반 개발
2-2. Props & State 기초
2-3. 단방향 데이터 흐름 & 양방향 데이터 바인딩 패턴
2-4. 스타일링 시스템 (StyleSheet & Flexbox)
🗝️ React Native는 컴포넌트(Component) 를 기본 단위로 앱을 구성.
import React from 'react';
import { Text, View } from 'react-native';
export default function App() {
return (
<View>
<Text>Hello, React Native!</Text>
</View>
);
}
View : 웹의 div와 비슷, "레이아웃 컨테이너"의 역할
Text : 텍스트 전용 컴포넌트
👉 React Native에서는 DOM이 아니라 네이티브 UI 컴포넌트로 렌더링됨.
React Native의 UI는 " 컴포넌트(Component) " 단위로 구성
React Native의 UI는 HTML이 아니라 네이티브 플랫폼의 컴포넌트들로 렌더링됩니다.
컴포넌트는 크게 '클래스형 컴포넌트' vs '함수형 컴포넌트'
import React, {Component} from "react";
import {View, Text} from 'react-native';
class App extends Component {
const name = ‘리액트’;
render(){
return(
<View>
<Text> {name} </Text>
</VIew>
);
} }
export default App;
import React from "react";
import {View, Text} from 'react-native';
const App = () => {
const name = ‘리액트’;
return(
<View>
<Text> {name} </Text>
</VIew>
}
export default App;
```
함수형 컴포넌트를 이용해 UI와 로직을 독립적이고 재사용 가능하게 관리
JSX를 사용해 HTML과 유사한 문법으로 UI를 작성
import { Text, View } from 'react-native';
export default function App() {
return (
<View>
<Text>Hello, React Native!</Text>
</View>
);
}
컴포넌트는 재사용성을 핵심으로 하며, 작은 단위의 UI 블록으로 쪼개는 방식
✅ JSX란?
JSX (JavaScript XML) 는 JavaScript 안에서
XML/HTML 같은 문법을 사용할 수 있게 해주는 문법입니다.
React 컴포넌트에서 UI를 선언적으로 작성할 수 있게 해줍니다.
const title = "Hello";
return <Text>{title}</Text>;
→ 위 코드는 JavaScript 안에서 XML을 사용하는 형태이며, Babel이 이를 다음처럼 변환.
React.createElement(Text, null, title)
function Greeting({ name }: { name: string }) {
return <Text>Hello, {name}!</Text>;
}
함수형 컴포넌트(Function Component) 는 컴포넌트를 함수처럼 정의하는 방식.
React 16.8부터는 상태 관리도 useState 등의 Hook을 통해 가능해졌고,
함수형이 클래스형보다 가볍고 읽기 쉽기 때문에 현재는 함수형이 표준.
function Greeting({ name }) {
return <Text>Hello, {name}</Text>;
}
props는 컴포넌트에 전달되는 외부 데이터
컴포넌트는 "순수 함수"처럼 동작 -> 동일한 입력(props)에 대해 동일한 출력(UI)을 제공.
React Native는 DOM이 없고, JSX가 네이티브 UI 컴포넌트로 매핑하고 렌더링됨.
📌 렌더링 과정 요약:
React 18 이후 RN도 Concurrent Rendering (동시성 렌더링)텍스트 지원
🧠 관련 용어 설명:
용어 | 설명 |
---|---|
Shadow Tree | React Native 내부에서 레이아웃 계산용으로 생성되는 트리. Flexbox를 기반으로 함. |
Bridge | JavaScript ↔ Native 간 데이터를 주고받는 통신 레이어. 성능 이슈의 핵심 포인트 중 하나. |
Renderer | 렌더링 엔진. React Native는 RN 전용 렌더러(RNRenderer)를 사용. |
Reconciliation | 상태(state)나 props가 변경되었을 때, 변경된 부분만 찾아서 UI를 업데이트하는 과정. |
Fiber | React 16에서 도입된 내부 아키텍처. UI 업데이트를 세분화하고 스케줄링할 수 있게 함. |
🏗️ Atomic Design 패턴:
컴포넌트 분리 기준 :
디자인 패턴 : Presentational vs Container Component 패턴
// Presentational
function UserCard({ name }) {
return <Text>{name}</Text>;
}
// Container
function UserCardContainer() {
const [name, setName] = useState("안다미로");
return <UserCard name={name} />;
}
역할을 나누어 컴포넌트를 분리하면 유지보수성이 높아짐.
// components/Button.tsx
export default function Button({ title, onPress }) {
return (
<TouchableOpacity onPress={onPress}>
<Text>{title}</Text>
</TouchableOpacity>
);
}
→ 여러 화면에서 같은 버튼 스타일과 동작을 재사용 가능
src/
└── components/
├── atoms/
│ └── Button.tsx
├── molecules/
│ └── LoginForm.tsx
└── organisms/
└── AuthScreen.tsx
부모 -> 자식 컴포넌트로 전달되는 '읽기 전용' 데이터.
불변(immutable) 속성 ==>> "수정 불가"!!
function Greeting({ name }: { name: string }) {
return <Text>Hello, {name}!</Text>;
}
export default function App() {
return <Greeting name="안다미로" />;
}
설명 -> App에서 Greeting으로 'name'이라는 prop 전달.
컴포넌트 내부에서 관리하는 동적 데이터
useState 'Hook'으로 선언.!
import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<View>
<Text>현재 카운트: {count}</Text>
<Button title="증가" onPress={() => setCount(count + 1)} />
</View>
);
}
설명 -> 버튼을 클릭하면 count 값이 업데이트되고, 화면이 리렌더링.
Props는 부모 컴포넌트가 자식 컴포넌트에 전달하는 읽기 전용 데이터.
UI를 구성하는 데 필요한 외부 데이터를 전달함.
마치 HTML의 태그 속성과 비슷한 역할을 하며, 컴포넌트를 재사용 가능하게 만들어줌.
function Greeting({ name }) {
return <Text>Hello, {name}</Text>;
}
<Greeting name="안다미로" />
State는 컴포넌트 내부에서 사용하는 변할 수 있는 데이터(상태)입니다.
상태가 변경되면 해당 컴포넌트는 자동으로 리렌더링**되어 변경사항이 UI에 반영
const [count, setCount] = useState(0);
항목 | Props | State |
---|---|---|
정의 | 외부에서 전달받는 데이터 | 내부에서 선언한 상태값 |
변경 가능 여부 | 불변 (읽기 전용) | 변경 가능 (setState 등) |
책임 주체 | 부모 컴포넌트 | 자신(또는 Context 등) |
용도 | 컴포넌트 구성/데이터 전달 | UI의 동적 변경 |
Props는 불변성 유지, State는 리렌더링 트리거
State 업데이트 시 RN의 Shadow Tree와 비교 후 필요한 부분만 업데이트.
useState는 '비동기적'으로 작동(즉시 반영되지 않을 수 있음)
🔁 State가 변경되면 무슨 일이 일어나는가??
🧠 렌더링 과정 in React Native
React Native는 DOM이나 Vritual DOM이 없음.
대신, 상태(State) 변경 시 다음 흐름으로 작동.
useState로 상태 변경 →
React Fiber에서 Shadow Tree 재구성 →
Yoga 엔진으로 레이아웃 계산 →
Bridge로 네이티브에 전달 →
실제 UI(Native View) 렌더링
❗ 비동기 상태 처리
setCount(count + 1);
console.log(count); // 여전히 이전 값 출력됨
✅ 함수형 업데이트 방식.
setCount(prev => prev + 1);
// 여러 단계 하위 컴포넌트에 props 넘기는 문제 발생
상태 종류 | 설명 | 대표 도구 |
---|---|---|
Local State | 컴포넌트 내부 상태 | useState, useReducer |
Global State | 여러 컴포넌트에서 공유하는 상태 | Context, Redux, Zustand |
Server State | API로부터 가져온 외부 데이터 | React Query, SWR |
Navigation State | 현재 화면, 파라미터 등 | React Navigation |
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
useEffect(() => {
const timeout = setTimeout(() => {
search(text);
}, 300);
return () => clearTimeout(timeout);
}, [text]);
데이터는 "위 -> 아래 ( 부모 -> 자식 )" 방향으로 전달됨.
ex)
function Child({ value }: { value: number }) {
return <Text>값: {value}</Text>;
}
export default function Parent() {
return <Child value={10} />;
}
설명 -> Parent에서 Child로 'value'이라는 prop 전달.
React-Native 자체는 "단방향 데이터 흐름"을 따르지만,
TextInput + useState 조합으로 " 양방향 '처럼' " 구현 가능.
import React, { useState } from 'react';
import { View, TextInput, Text } from 'react-native';
export default function InputExample() {
const [text, setText] = useState('');
return (
<View>
<TextInput
value={text}
onChangeText={setText}
placeholder="텍스트를 입력하세요"
style={{ borderWidth: 1, padding: 8 }}
/>
<Text>입력값: {text}</Text>
</View>
);
}
사용자가 '입력'을 하면 'onChangeText' -> 'setText' 호출
state 변경 -> UI 자동 업데이트.
즉, "단방향 흐름을 기반으로 한 양방향 구현"
React Native는 "단방향 데이터 흐름"을 기본 원칙으로 가짐.
부모 -> 자식 방향으로만 데이터가 흐름.!
React Native에서는 사용자의 터치 이벤트를 처리하기 위해
전용 컴포넌트와 콜백 함수를 사용합니다.
import { Button, Alert } from 'react-native';
<Button title="눌러보세요" onPress={() => Alert.alert("눌림")} />
const handlePress = () => {
console.log("사용자가 버튼을 눌렀습니다");
};
컴포넌트 | 설명 |
---|---|
TouchableOpacity | 터치 시 투명도 변화 |
TouchableHighlight | 터치 시 배경 강조 |
Pressable | 다양한 상태별 스타일링 지원 |
Gesture Handler | 고급 제스처 처리 (swipe 등) |
<Pressable onPressIn={...} onLongPress={...} onPressOut={...} />
<KeyboardAvoidingView behavior="padding">
<TextInput />
</KeyboardAvoidingView>
✅ Focus 제어, ScrollView 연동.
<TextInput value={email} onChangeText={setEmail} keyboardType="email-address" />
<TextInput value={password} onChangeText={setPassword} secureTextEntry />
<TouchableOpacity onPress={handlePress} activeOpacity={0.6}>
<Text>로그인</Text>
</TouchableOpacity>
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
padding: 16,
},
});
속성 | 설명 |
---|---|
flex , flexDirection | 레이아웃 구성 |
padding , margin | 여백 조정 |
alignItems , justifyContent | 정렬 방식 |
color , fontSize | 텍스트 스타일링 |
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }} />
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }} />
속성 | 설명 |
---|---|
flexDirection | row , column |
justifyContent | flex-start , center , space-between |
alignItems | flex-start , center , stretch |
✅ 반응형 디자인
Dimensions.get('window'), useWindowDimensions()
퍼센트 단위 또는 Flex 기반 구성
✅ 다크모드 대응
const colorScheme = useColorScheme();
const isDark = colorScheme === 'dark';
✅ 테마 시스템.
const styles = StyleSheet.create({
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>로그인</Text>
</TouchableOpacity>
const styles = StyleSheet.create({
button: {
backgroundColor: '#2196F3',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontWeight: 'bold',
},
});