티스토리 뷰
[React-native] 앱 개발을 하며 마주한 IOS secureTextEntry 관련 이슈 톺아보기 - 2. 수동으로 패스워드 타입 구현하기
AlgoRoot 2022. 12. 12. 12:53Implement password types manually
안녕하세요 지난번 이슈를 해결하는 과정에서 이어져 수동으로 TextInput 비밀번호 타입을 구현했던 과정에 대해 포스팅해보려고 합니다.
- 리액트 네이티브 패키지에서 네이티브 언어 바꾸었던 시도
처음에는 onChangeText에서 value값을 바로 '•' 으로 replace 하는 방법을 썼었는데 이렇게 되면 vlaue가
'••••def' 형태로 저장되어 유저가 친 비밀번호가 무엇인지 알 수 없었습니다.
여러 시도 끝에 저는 TextInput에서 제공하는 여러 가지의 props를 활용하여 기능 구현에 성공했습니다.
구현을 위해서는 네 가지의 state가 필요합니다.
* onKeyPress로는 유저가 값들을 선택했을 때 (블럭처리했을 때)까지 감지할 수 없기 때문에
onSelectionChange로 value를 잡아왔습니다.
1. show : input이 텍스트로 보여질건지, bullet point('•') 으로 보일 것인지에 대한 여부
2. valuePW : 유저가 실제로 입력한 값 e.g. qwer1234
3. selected: onSelectionChange에서 제공하는 selection target evnet 값 > selection: { start: number; end: number; };
4. isSelected: 유저가 해당 인풋에서 selection을 했는지 안했는지에 대한 여부
const [show, setShow] = React.useState(false);
const [valuePW, setValuePW] = React.useState('');
const [selected, setSelected] = React.useState<TextInputSelectionChangeEventData['selection']>({ start: 0, end: 0 });
const [isSelected, setIsSelected] = React.useState(false);
Input Element
비밀번호(bullet point)로 선택했을 경우에는 value값들을 '•' 으로 replace 시켜줍니다.
<Input
...
value={show[1] ? valuePW : valuePW.replace(/./g, '•')}
onChangeText={handleChangePW}
onSelectionChange={handleSelectChange}
onKeyPress={handleKeyPress}
InputRightElement={show[1] ? ShowIcon(1) : HideIcon(1)}
/>
onSelectionChange
: Callback that is called when the text input selection is changed.
유저가 입력한 key 값을 onKeyPress 함수를 통해 상태값으로 저장합니다. 다만 key 값이 'Backspace'인 경우 'Backspace'로 저장이 되기 때문에 이때는 수동으로 입력한 수만큼 문자를 삭제해주는 과정을 거쳐야 합니다.
보통은 인풋 값을 삭제할 때 가장 최근 입력한 값을 지우게 되지만, 유저가 임의로 커서(cursor)를 문자 중간에 두거나, 드래그를 해 값의 영역을 선택해서 값을 지울 경우를 고려하면 커서가 어느 부분에 위치 해 있는지도 감지를 할 수 있어야 합니다.
이는 onSelectionChange 함수에서 감지할 수 있습니다. 인풋 값을 선택했을 때 처음 값(start)과 끝 값(end)의 위치(index)를 제공해줍니다.
export interface TextInputSelectionChangeEventData extends TargetedEvent {
selection: {
start: number;
end: number;
};
}
onSelectionChange?: ((e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => void) | undefined;
onSelectionChange에서 제공해주는 selection을 상태값으로 저장합니다. 여기에 추가로 isSelected라는 상태를 만들어서 유저가 인풋 값을 선택을 했는지 안 했는지에 대한 상태값을 set 해줍니다.
(start와 end 값이 같으면 selected하지 않은 상태라 false로 set 해줍니다.)
const handleSelectChange = (e: { nativeEvent: { selection: TextInputSelectionChangeEventData['selection'] } }) => {
const selection = e.nativeEvent.selection;
setSelected(selection);
if (selection.start === selection.end) setIsSelected(false);
else return setIsSelected(true);
};
onKeyPress
: Callback that is called when a key is pressed. This will be called with { nativeEvent: { key: keyValue } } where keyValue is 'Enter' or 'Backspace' for respective keys and the typed-in character otherwise including ' ' for space.
이제 유저가 입력한 key를 어떠한 경우에서도 수동적으로 따라갈 수 있게 만들 수 있습니다.
key값이 'Backspace'인 경우에 입력된 문자를 삭제해 줘야 하는데 이때 isSelected에 따라 분기처리를 해줘야 합니다.
Key === 'Backspace'
1. 커서의 위치가 어느 곳에 있든 한 문자만 삭제할 경우
(0 ~ start index -1) + (end index ~)
setValuePW( (v) => v.slice(0, selected.start - 1) + v.slice(selected.end));
2. 값들이 선택되었을 경우
(0 ~ start index) + (end index ~)
setValuePW((v) => v.slice(0, selected.start) + v.slice(selected.end));
Key!== 'Backspace'
1. 커서가 인풋 값의 마지막에 위치할 경우
valuePW.length === selected.end
setValuePW((v) => v + key);
2. 커서가 인풋 값의 중간이나 처음에 위치할 경우
setValuePW( (v) => v.slice(0, selected.start) + key + v.slice(selected.end, valuePW.length));
const handleKeyPress = (
e: NativeSyntheticEvent<TextInputKeyPressEventData>,
) => {
const key = e.nativeEvent.key;
if (key === 'Backspace') {
if (!isSelected)
setValuePW(
(v) => v.slice(0, selected.start - 1) + v.slice(selected.end),
);
else
setValuePW((v) => v.slice(0, selected.start) + v.slice(selected.end));
return;
}
if (valuePW.length === selected.end) {
setValuePW((v) => v + key);
}
setValuePW(
(v) =>
v.slice(0, selected.start) +
key +
v.slice(selected.end, bulletPointPW.length),
);
};
onChange
onChange 함수에서는 인풋 값이 빈 값일 때 value state값도 빈 값으로 바꿔주기만 하면 됩니다.
const handleChangePW = (password: string) => {
if (password === '') setValuePW('');
};
테스트까지 완료했고 어떠한 경우에서도 잘 작동하는 것을 확인했습니다. 지난 포스팅에 걸쳐 하나의 이슈를 깊이 파고들어 봤는데요. 해당 과정을 통해서 알게 된 지식들이 많았습니다.
시간을 투자하는 것은 어떤 결과가 나오든 의미 있는 일이라는 생각이 듭니다. 또 기록을 통해 지나칠 수 있었던 부분도 다지 되짚어 보게 되어 개발자로서 더 탄탄해진 것 같습니다.
'Frontend > React-native' 카테고리의 다른 글
[ReactNative] 유연하고 재사용 가능한 제네릭타입으로 리액트네이티브 내비게이션 관리하기 (0) | 2023.02.19 |
---|---|
[Patch-package] NPM 패키치 간단하게 패치(patch)하는 법 (0) | 2022.12.14 |
[React-native] 앱 개발을 하며 마주한 IOS secureTextEntry 관련 이슈 톺아보기 - 1. 패키지 코드 변경하기 (0) | 2022.12.11 |
[React-native] 리액트 네이티브 Common/Custom Header 관리하기 (0) | 2022.12.10 |
[React-native] IOS, android에서 디바이스 설정 창 (app setting) 열기 및 app 밖의 상태 감지하기 (0) | 2022.10.10 |
- Total
- Today
- Yesterday
- 프로그래머스 자바스크립트
- 백준
- 모두를위한컴퓨터과학
- javascript
- reactquery
- 리액트
- 자바스크립트알고리즘
- 자바스크립트 클로저
- React
- 리액트네이티브
- 자바스크립트 비동기 처리
- 알고리즘자바스크립트
- cs50
- 프로그래머스
- 네트워크
- 프로그래머스 베스트앨범 자바스크립트
- 실전프로젝트
- GIT
- 클로저
- html
- github
- 타입스크립트
- python
- React Query
- 무한스크롤
- 자바스크립트
- network
- 모두를 위한 컴퓨터 과학
- css
- 항해99
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |