TextInput은 사용자로부터 텍스트를 입력받는 유일한 Core Component입니다.

모바일에서 텍스트 입력은 웹보다 훨씬 복잡합니다. 키보드가 화면을 가리고, 플랫폼마다 키보드 타입이 다르며, 자동 완성 동작도 다릅니다.


기본 사용법

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

function BasicInput() {
  const [text, setText] = useState('');

  return (
    <View style={styles.container}>
      <Text style={styles.label}>이름</Text>
      <TextInput
        style={styles.input}
        value={text}
        onChangeText={setText}  // onChange가 아닌 onChangeText!
        placeholder="이름을 입력하세요"
        placeholderTextColor="#999"
      />
      <Text>입력값: {text}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 20 },
  label: { fontSize: 14, color: '#666', marginBottom: 8 },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    fontSize: 16,
    backgroundColor: 'white',
  },
});

onChangeText는 문자열을 직접 전달합니다. 웹의 onChange처럼 이벤트 객체가 아닙니다. 이 차이를 모르면 e.target.value를 쓰려다 에러가 납니다.


키보드 타입별 설정

TSX
// 이메일 입력
<TextInput
  keyboardType="email-address"
  autoCapitalize="none"
  autoCorrect={false}
  textContentType="emailAddress"  // iOS 자동 완성
/>

// 비밀번호 입력
<TextInput
  secureTextEntry           // 비밀번호 마스킹
  autoCapitalize="none"
  textContentType="password"
/>

// 숫자 입력
<TextInput
  keyboardType="numeric"     // 숫자 키보드
  // keyboardType="number-pad"  // 숫자 패드만
  // keyboardType="decimal-pad" // 소수점 포함 숫자
  // keyboardType="phone-pad"   // 전화번호
/>

// 검색 입력
<TextInput
  returnKeyType="search"    // 리턴 키를 '검색'으로
  enablesReturnKeyAutomatically  //  값이면 리턴  비활성화
  onSubmitEditing={() => handleSearch()}
/>

// 여러 줄 입력
<TextInput
  multiline
  numberOfLines={4}
  textAlignVertical="top"   // Android에서 텍스트 위쪽 정렬
  style={{ height: 120, textAlignVertical: 'top' }}
/>

returnKeyType 옵션

표시용도
done완료단일 입력 완료
next다음다음 입력으로 이동
search검색검색 실행
send전송메시지 전송
go이동URL 이동

키보드 회피 처리

키보드가 입력 필드를 가리는 문제는 모바일 개발의 고전적인 이슈입니다.

TSX
import {
  KeyboardAvoidingView,
  Platform,
  ScrollView,
  StyleSheet,
} from 'react-native';

function KeyboardAvoidingForm() {
  return (
    <KeyboardAvoidingView
      style={styles.container}
      // iOS에서는 padding, Android에서는 height 방식이  동작
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      keyboardVerticalOffset={Platform.OS === 'ios' ? 64 : 0}
    >
      <ScrollView
        contentContainerStyle={styles.scrollContent}
        keyboardShouldPersistTaps="handled"
      >
        <TextInput style={styles.input} placeholder="이름" />
        <TextInput style={styles.input} placeholder="이메일" />
        <TextInput style={styles.input} placeholder="메시지" multiline />
      </ScrollView>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  scrollContent: { padding: 20 },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    marginBottom: 16,
    fontSize: 16,
  },
});

키보드 닫기

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

// 배경을 탭하면 키보드 닫기
function DismissKeyboard({ children }: { children: React.ReactNode }) {
  return (
    <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
      <View style={{ flex: 1 }}>
        {children}
      </View>
    </TouchableWithoutFeedback>
  );
}

다음 입력으로 포커스 이동

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

function FocusChain() {
  const emailRef = useRef<TextInput>(null);
  const passwordRef = useRef<TextInput>(null);

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="이름"
        returnKeyType="next"
        // 리턴  누르면 이메일 필드로 포커스 이동
        onSubmitEditing={() => emailRef.current?.focus()}
        blurOnSubmit={false}
      />
      <TextInput
        ref={emailRef}
        style={styles.input}
        placeholder="이메일"
        returnKeyType="next"
        onSubmitEditing={() => passwordRef.current?.focus()}
        blurOnSubmit={false}
      />
      <TextInput
        ref={passwordRef}
        style={styles.input}
        placeholder="비밀번호"
        secureTextEntry
        returnKeyType="done"
        onSubmitEditing={() => handleSubmit()}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 20 },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    marginBottom: 12,
    fontSize: 16,
  },
});

입력값 포맷팅

TSX
// 전화번호 자동 포맷팅
function PhoneInput() {
  const [phone, setPhone] = useState('');

  const formatPhone = (text: string) => {
    // 숫자만 추출
    const numbers = text.replace(/[^\d]/g, '');
    // 하이픈 추가
    if (numbers.length <= 3) return numbers;
    if (numbers.length <= 7) return `${numbers.slice(0, 3)}-${numbers.slice(3)}`;
    return `${numbers.slice(0, 3)}-${numbers.slice(3, 7)}-${numbers.slice(7, 11)}`;
  };

  return (
    <TextInput
      value={phone}
      onChangeText={(text) => setPhone(formatPhone(text))}
      keyboardType="phone-pad"
      placeholder="010-1234-5678"
      maxLength={13}
    />
  );
}

// 금액 입력 (콤마 포맷)
function MoneyInput() {
  const [amount, setAmount] = useState('');

  const formatMoney = (text: string) => {
    const numbers = text.replace(/[^\d]/g, '');
    return numbers.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  };

  return (
    <TextInput
      value={amount}
      onChangeText={(text) => setAmount(formatMoney(text))}
      keyboardType="numeric"
      placeholder="0"
    />
  );
}

포커스 상태 스타일링

TSX
function FocusStyleInput() {
  const [isFocused, setIsFocused] = useState(false);

  return (
    <TextInput
      style={[
        styles.input,
        isFocused && styles.focused,
      ]}
      onFocus={() => setIsFocused(true)}
      onBlur={() => setIsFocused(false)}
      placeholder="포커스 시 스타일 변경"
    />
  );
}

const styles = StyleSheet.create({
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    fontSize: 16,
  },
  focused: {
    borderColor: '#007AFF',
    borderWidth: 2,
  },
});

정리

  • onChangeText는 문자열을 직접 전달합니다 (웹의 e.target.value와 다름)
  • keyboardType으로 입력에 적합한 키보드를 보여주세요
  • KeyboardAvoidingView로 키보드가 입력을 가리지 않게 하세요
  • refonSubmitEditing으로 다음 입력으로 자동 포커스 이동을 구현하세요
  • 전화번호, 금액 등은 onChangeText에서 포맷팅 함수를 적용하세요
댓글 로딩 중...