TextInput — 사용자 입력 처리와 키보드 대응
TextInput은 사용자로부터 텍스트를 입력받는 유일한 Core Component입니다.
모바일에서 텍스트 입력은 웹보다 훨씬 복잡합니다. 키보드가 화면을 가리고, 플랫폼마다 키보드 타입이 다르며, 자동 완성 동작도 다릅니다.
기본 사용법
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를 쓰려다 에러가 납니다.
키보드 타입별 설정
// 이메일 입력
<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 이동 |
키보드 회피 처리
키보드가 입력 필드를 가리는 문제는 모바일 개발의 고전적인 이슈입니다.
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,
},
});
키보드 닫기
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>
);
}
다음 입력으로 포커스 이동
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,
},
});
입력값 포맷팅
// 전화번호 자동 포맷팅
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"
/>
);
}
포커스 상태 스타일링
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로 키보드가 입력을 가리지 않게 하세요ref와onSubmitEditing으로 다음 입력으로 자동 포커스 이동을 구현하세요- 전화번호, 금액 등은
onChangeText에서 포맷팅 함수를 적용하세요
댓글 로딩 중...