React Native의 Core Components는 플랫폼별 네이티브 뷰로 매핑되는 기본 빌딩 블록입니다.

웹 개발에서 HTML 태그를 사용하듯, React Native에서는 Core Components를 사용합니다. 하지만 단순히 이름만 바뀐 게 아니라 동작 방식과 제약 조건 이 다릅니다.


View — 모든 레이아웃의 기본

View는 웹의 <div>에 해당하는 컨테이너 컴포넌트입니다. 모든 레이아웃의 시작점이죠.

TSX
import { View, StyleSheet } from 'react-native';

// View는 기본적으로 flexDirection: 'column'
function CardLayout() {
  return (
    <View style={styles.card}>
      <View style={styles.header}>
        {/* 헤더 영역 */}
      </View>
      <View style={styles.body}>
        {/* 본문 영역 */}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    backgroundColor: 'white',
    borderRadius: 12,
    padding: 16,
    // 웹과 달리 기본이 column 방향
    // flexDirection: 'column'이 기본값
  },
  header: {
    borderBottomWidth: 1,
    borderBottomColor: '#eee',
    paddingBottom: 12,
  },
  body: {
    paddingTop: 12,
  },
});

웹 div와의 주요 차이점

  • 기본 flexDirectioncolumn (웹은 row)
  • display: 'flex'가 기본값 (웹처럼 block이 아님)
  • 직접 텍스트를 넣을 수 없음 — 반드시 <Text>로 감싸야 함
  • overflow: 'hidden'이 아닌 overflow: 'visible'이 기본값 (Android)

면접에서 "React Native의 View와 웹의 div 차이점"을 물으면, flexDirection 기본값 차이를 꼭 언급하세요. 이걸 모르면 레이아웃이 의도와 다르게 나옵니다.


Text — 텍스트 표시의 유일한 방법

React Native에서 텍스트를 표시하려면 반드시 <Text> 컴포넌트를 사용해야 합니다.

TSX
import { Text, StyleSheet } from 'react-native';

function TextExample() {
  return (
    <>
      {/* 기본 텍스트 */}
      <Text style={styles.title}>제목입니다</Text>

      {/* 중첩 텍스트 — 인라인 스타일링 */}
      <Text style={styles.body}>
        이것은 <Text style={styles.bold}>굵은 텍스트</Text>
        <Text style={styles.highlight}> 강조 텍스트</Text>를 포함합니다.
      </Text>

      {/* 줄 수 제한 */}
      <Text numberOfLines={2} ellipsizeMode="tail">
        매우 긴 텍스트가 있을 때 2줄로 제한하고
        나머지는 말줄임표로 표시할 수 있습니다.
        이 부분은 잘려서 보이지 않습니다.
      </Text>

      {/* 선택 가능한 텍스트 */}
      <Text selectable>이 텍스트는 길게 눌러서 복사할 수 있습니다.</Text>
    </>
  );
}

const styles = StyleSheet.create({
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#1a1a1a',
  },
  body: {
    fontSize: 16,
    lineHeight: 24,
    color: '#333',
  },
  bold: {
    fontWeight: 'bold',
  },
  highlight: {
    color: '#007AFF',
    backgroundColor: '#E5F0FF',
  },
});

Text의 스타일 상속

웹과 다른 중요한 특성입니다.

TSX
// 웹에서는 부모의 font-size, color 등이 자식에게 상속됨
// React Native에서는 Text 컴포넌트 안에서만 상속됨

function StyleInheritance() {
  return (
    // View의 스타일은 Text에 상속되지 않음!
    <View style={{ fontSize: 20 }}>
      <Text>이 텍스트는 fontSize 20이 적용되지 않습니다</Text>
    </View>
  );
}

function CorrectInheritance() {
  return (
    // Text 안의 Text는 스타일이 상속됨
    <Text style={{ fontSize: 20, color: 'blue' }}>
      부모 텍스트
      <Text style={{ fontWeight: 'bold' }}>
        {/* fontSize 20, color blue가 상속됨 */}
        자식 텍스트도 파란색이고 20px
      </Text>
    </Text>
  );
}

Image — 이미지 표시

TSX
import { Image, StyleSheet } from 'react-native';

function ImageExample() {
  return (
    <>
      {/* 로컬 이미지 — require 사용 */}
      <Image
        source={require('./assets/logo.png')}
        style={styles.logo}
      />

      {/* 네트워크 이미지 — uri와 크기 필수 */}
      <Image
        source={{ uri: 'https://example.com/photo.jpg' }}
        style={styles.networkImage}
        resizeMode="cover"
      />

      {/* Base64 이미지 */}
      <Image
        source={{ uri: 'data:image/png;base64,...' }}
        style={styles.logo}
      />
    </>
  );
}

const styles = StyleSheet.create({
  logo: {
    width: 100,
    height: 100,
  },
  networkImage: {
    width: 300,
    height: 200,
    borderRadius: 8,
  },
});

로컬 vs 네트워크 이미지 차이

항목로컬 이미지네트워크 이미지
소스require('./path'){ uri: 'https://...' }
크기 지정자동 감지 가능반드시 width/height 지정
로딩즉시비동기
캐싱번들에 포함별도 캐싱 필요

네트워크 이미지에 width와 height를 지정하지 않으면 아무것도 보이지 않습니다. 이 부분에서 많이 헷갈렸습니다.

resizeMode 옵션

TSX
// 이미지를 어떻게 맞출지 결정
<Image
  source={{ uri: imageUrl }}
  style={{ width: 200, height: 200 }}
  resizeMode="cover"    // 비율 유지, 영역 꽉 채움 (잘릴 수 있음)
  // resizeMode="contain"  // 비율 유지, 영역 안에 들어감 (여백 가능)
  // resizeMode="stretch"  // 비율 무시, 영역에 맞춤
  // resizeMode="center"   // 원본 크기로 중앙 배치
/>

ImageBackground — 배경 이미지

TSX
import { ImageBackground, Text, StyleSheet } from 'react-native';

function HeroBanner() {
  return (
    <ImageBackground
      source={{ uri: 'https://example.com/banner.jpg' }}
      style={styles.banner}
      resizeMode="cover"
    >
      {/* 이미지 위에 컨텐츠 배치 */}
      <Text style={styles.bannerText}>환영합니다!</Text>
    </ImageBackground>
  );
}

const styles = StyleSheet.create({
  banner: {
    width: '100%',
    height: 200,
    justifyContent: 'center',
    alignItems: 'center',
  },
  bannerText: {
    color: 'white',
    fontSize: 28,
    fontWeight: 'bold',
  },
});

JSX 주의사항

텍스트는 반드시 Text로 감싸기

TSX
// 잘못된 예 — 크래시 발생
function Wrong() {
  return (
    <View>
      안녕하세요  {/* 에러! View 안에 직접 텍스트 불가 */}
    </View>
  );
}

// 올바른 예
function Correct() {
  return (
    <View>
      <Text>안녕하세요</Text>
    </View>
  );
}

조건부 렌더링 주의

TSX
function ConditionalRender({ count }: { count: number }) {
  return (
    <View>
      {/* 위험: count가 0이면 "0"이 텍스트로 렌더링되어 크래시 */}
      {count && <Text>알림 {count}개</Text>}

      {/* 안전: Boolean으로 명시적 변환 */}
      {count > 0 && <Text>알림 {count}개</Text>}

      {/* 또는 삼항 연산자 사용 */}
      {count > 0 ? <Text>알림 {count}개</Text> : null}
    </View>
  );
}

웹 React에서는 0이 렌더링되어도 문제없지만, React Native에서는 View 안에 숫자가 직접 렌더링되면 크래시가 납니다. 이 차이를 알아두면 디버깅 시간을 크게 줄일 수 있습니다.


정리

  • View는 기본 Flexbox 컨테이너이며, flexDirection 기본값이 column 입니다
  • Text는 텍스트를 표시하는 유일한 방법이고, 스타일 상속은 Text 내부에서만 동작합니다
  • Image의 네트워크 이미지는 ** 반드시 크기를 지정 **해야 합니다
  • JSX에서 0, '' 같은 falsy 값이 View 안에 렌더링되지 않도록 조건부 렌더링에 주의하세요
댓글 로딩 중...