티스토리 뷰

반응형

 

Implement password types manually

 

안녕하세요 지난번 이슈를 해결하는 과정에서 이어져 수동으로 TextInput 비밀번호 타입을 구현했던 과정에 대해 포스팅해보려고 합니다.

 

 

- 리액트 네이티브 패키지에서 네이티브 언어 바꾸었던 시도 

 

[React-native] 앱 개발을 하며 마주한 IOS secureTextEntry 관련 이슈 톺아보기 - 1. 패키지 코드 변경하기

안녕하세요. 오늘은 최근 React native로 앱 개발을 하며 마주했던 이슈를 파헤쳤던 과정을 회고와 함께 말씀드리고자 합니다. 사실 정확히 말하면 이슈라고 할 수 없는 'IOS에서의 의도적인 행동'이

algoroot.tistory.com

 

처음에는 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('');
  };

 


테스트까지 완료했고 어떠한 경우에서도 잘 작동하는 것을 확인했습니다. 지난 포스팅에 걸쳐 하나의 이슈를 깊이 파고들어 봤는데요. 해당 과정을 통해서 알게 된 지식들이 많았습니다. 

 

시간을 투자하는 것은 어떤 결과가 나오든 의미 있는 일이라는 생각이 듭니다. 또 기록을 통해 지나칠 수 있었던 부분도 다지 되짚어 보게 되어 개발자로서 더 탄탄해진 것 같습니다. 

반응형