
import React from 'react';
import {
Pressable,
PressableProps,
StyleSheet,
TextInput,
TextInputProps,
} from 'react-native';
const styles = StyleSheet.create({
container: {
width: 44,
height: 44,
borderRadius: 12,
backgroundColor: '#E7ECF9',
justifyContent: 'center',
},
textInput: {
fontSize: 16,
textAlign: 'center',
},
});
export type SingleDigitInputProps = {
onChangeText: NonNullable<TextInputProps['onChangeText']>;
value: NonNullable<TextInputProps['value']>;
};
export type SingleDigitInputRef = {
focus: () => void;
blur: () => void;
};
export default React.forwardRef<
SingleDigitInputRef,
SingleDigitInputProps
>(function SingleDigitInput(props, ref) {
const inputRef = React.useRef<TextInput>(null);
React.useImperativeHandle(
ref,
() => ({
focus: () => {
inputRef.current?.focus();
},
blur: () => {
inputRef.current?.blur();
},
}),
[],
);
const handlePress: NonNullable<PressableProps['onPress']> =
React.useCallback(() => {
inputRef.current?.focus();
}, []);
return (
<Pressable style={styles.container} onPress={handlePress}>
<TextInput
ref={inputRef}
style={styles.textInput}
value={props.value}
onChangeText={props.onChangeText}
maxLength={1}
/>
</Pressable>
);
});
이렇게 한 칸 입력을 만들고
import SingleDigitInput, {
SingleDigitInputProps,
SingleDigitInputRef,
} from './SingleDigitInput';
import React from 'react';
import {StyleSheet, View} from 'react-native';
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'space-between',
alignSelf: 'stretch',
},
});
const MAX_DIGITS = 6
export default function MultipleDigitsInput() {
const [singleDigits, setSingleDigits] = React.useState<string[]>([]);
const addDigit = React.useCallback(
(digit: string) => {
if (digit.length > 1) {
return;
}
setSingleDigits(prev => {
if (prev.length >= MAX_DIGITS) {
return prev;
}
return [...prev, digit];
});
},
[setSingleDigits],
);
const removeDigit = React.useCallback(
({index}: {index: number}) => {
setSingleDigits(prev => {
if (prev.length === 0) {
return prev;
}
return [...prev.slice(0, index), ...prev.slice(index + 1)];
});
},
[setSingleDigits],
);
const handleChangeSingleDigit: (
index: number,
) => SingleDigitInputProps['onChangeText'] = React.useCallback(
index => text => {
if (text.length > 1 && index < MAX_DIGITS - 1) {
refs.current[index + 1]?.focus();
return;
}
if (text.length === 1 && index < MAX_DIGITS - 1) {
addDigit(text);
refs.current[index + 1]?.focus();
return;
}
if (text.length === 1 && index === MAX_DIGITS - 1) {
addDigit(text);
return;
}
if (text.length === 0 && index > 0) {
refs.current[index - 1]?.focus();
removeDigit({index: index});
return;
}
if (text.length === 0 && index === 0) {
removeDigit({index: index});
return;
}
},
[addDigit, removeDigit],
);
const refs = React.useRef<SingleDigitInputRef[]>(
Array.from({length: MAX_DIGITS}),
);
return (
<View style={styles.container}>
{Array.from({length: MAX_DIGITS}).map((_, index) => (
<SingleDigitInput
key={`${index}`}
value={singleDigits[index] || ''}
ref={r => r && (refs.current[index] = r)}
onChangeText={handleChangeSingleDigit(index)}
/>
))}
</View>
);
}
이렇게 여러 칸 입력을 만든다
https://snack.expo.dev/@orlein/six-digits-input
결과물
forwardRef의 <T, P> 순서를 파라미터 순서에 맞춰 <P, T>로 하지 않았을까?useImperativeHandle라는걸 굳이 써야하나?export default function .... 형태를 좋아하는 이유?StyleSheet 왜씀 딴거쓰지
잘 읽었습니다. 좋은 정보 감사드립니다.