안녕하세요 이번에 회사 앱에 flow를 깊게 확인하기 위해 이것저것 해보는 와중 제 눈에 띈 것이 하나 있습니다.
바로 Modal 입니다.
Modal은 앱에서 흔히 볼 수 있는 UI입니다.
Modal을 사용하는 곳에서는 항상 기본적으로 state 1개와 함수 2개로 구성이 되어있었습니다.
const [isModalOpened, setIsModalOpened] = useState(false);
const closeModal = () => {
setModalOpened(false);
};
const openModal = () => {
setModalOpened(true);
};
이런 똑같은 코드가 반복이 되는 것이 보기가 싫어 리팩토링을 해보도록 하겠습니다.
구현 단계
1차 구현
interface ModalHandle {
openModal: () => void;
closeModal: () => void;
}
const useModal = (): [boolean, ModalHandle] => {
const [isModalOpened, setIsModalOpened] = useState<boolean>(false);
const closeModal = (): void => {
setIsModalOpened(false);
};
const openModal = (): void => {
setIsModalOpened(true);
};
const modalHandle: ModalHandle = {
openModal,
closeModal,
};
return [isModalOpened, modalHandle];
};
export default useModal;
단순하게 Modal의 state 값과 handler(open, close)만 return 하고 있습니다.
이제 반복되는 코드를 지울 수 있겠다고 생각했었습니다.
유저 입장에서 놓친 부분이 있을까? 하고 고민을 하던 도중 놓친 케이스가 떠올랐습니다.
안드로이드 유저 같은 경우 backbutton을 통해 Modal을 닫는 유저도 존재합니다.
바로 backbutton에 대한 케이스를 정리했습니다.
CASE
- backbutton을 클릭 시 Modal을 close 한다.
- 기존에 backbutton 클릭 시 이벤트가 존재한다면 Modal이 닫혀있는 경우라면 그 이벤트를 실행해야 한다.
- backbutton을 클릭 시 Modal을 close 하고 싶지 않은 경우도 존재할 수 있다.
- UX적으로 사용자가 꼭 확인해야 하는 Modal이라면 이런 경우도 존재할 수 있다는 가능성을 열어놨습니다.
- UX적으로 사용자가 꼭 확인해야 하는 Modal이라면 이런 경우도 존재할 수 있다는 가능성을 열어놨습니다.
위에 적은 CASE를 고려하여 다시 구현을 해주도록 하겠습니다.
최종 구현
import { useState, useEffect } from 'react';
import { BackHandler } from 'react-native';
interface ModalOptions {
preventClose?: boolean;
onBackHandler?: () => boolean;
}
interface ModalHandle {
openModal: () => void;
closeModal: () => void;
}
const useModal = (options?: ModalOptions): [boolean, ModalHandle] => {
const [isModalOpened, setIsModalOpened] = useState<boolean>(false);
const closeModal = (): void => {
if (options?.preventClose) {
return;
}
setIsModalOpened(false);
};
const openModal = (): void => {
setIsModalOpened(true);
};
useEffect(() => {
const backAction = (): boolean => {
if (options?.preventClose) {
return true;
}
if (isModalOpened) {
closeModal();
return true;
}
if (options?.onBackHandler) {
return options.onBackHandler();
}
return false;
};
const originalBackHandler = BackHandler.addEventListener('hardwareBackPress', backAction);
const originalCallback = originalBackHandler.remove;
originalBackHandler.remove = (): void => {
if (isModalOpened) {
closeModal();
} else {
originalCallback();
}
};
return (): void => originalBackHandler.remove();
}, [isModalOpened, options?.onBackHandler, options?.preventClose]);
const modalHandle: ModalHandle = {
openModal,
closeModal,
};
return [isModalOpened, modalHandle];
};
export default useModal;
코드 설명
options를 통해 2개의 파라미터를 받습니다.
- preventClose : Modal이 열려있을 때 backbutton을 누를 시 Modal을 닫을지 말지 여부를 결정하는 boolean 값입니다
- onBackHandler : Modal이 닫혀있을 때 backbutton을 누를 시 실행할 함수입니다.
'개발' 카테고리의 다른 글
useDebounce를 활용하기 (1) | 2023.06.07 |
---|---|
React Native Chip을 구현해보자 (0) | 2023.05.26 |
React Native 나만의 checkbox 구현하기 ✅ (0) | 2023.05.16 |
내 입맛에 맞게 useList를 구현하기 (0) | 2023.05.10 |
useCodePush 구현하기 (3) | 2023.04.24 |