개발일지
[React-Native] Alert API 공통으로 사용할 수 있도록 만들기 본문
React-Native에는 Alert API를 활용하여 사용자에게 메시지를 보여주고, 버튼 목록을 제공하여 특정 동작을 사용자가 선택할 수 있습니다.
제 프로젝트에는 게시글 삭제, 작성 중 뒤로가기, 로그인 안내 등 다양한 곳에서 Alert를 사용하여 사용자에게 안내를 해주고 있습니다.
문제는 Alert API에는 파라미터가 총 3가지가 필요한데, 이걸 그대로 사용하는 곳에서 작성하게 되면 코드의 양이 너무나도 많아지게 됩니다.
const createThreeButtonAlert = () =>
Alert.alert('Alert Title', 'My Alert Msg', [
{
text: 'Ask me later',
onPress: () => console.log('Ask me later pressed'),
},
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{text: 'OK', onPress: () => console.log('OK Pressed')},
]);
이런식으로, 하나의 알러트를 위한 코드가 너무나도 길다고 생각되어, 한 곳에서 관리하고 호출하는 곳에서는 간단하게 작성하고 싶었습니다.
1. 타입 지정해주기
먼저 이 Alert가 사용될 부분을 정하고, 해당 부분에서 어떤 Title, Message, Button이 사용될 것인지를 정해야 합니다.
위에서 말씀드린 것처럼, 저는 삭제, 작성, 수정화면 등에서 사용하기에 사용하는 화면에 따라 타입을 나누었습니다.
그리고 해당 화면에서 사용될 Title, Message, Button을 작성했습니다.
const alertMessage = {
DELETE_TITLE: '정말로 해당 게시글을 삭제하시겠습니까?',
DELETE_MESSAGE: '삭제 후 데이터복구는 어려워요 🥺',
DELETE_BUTTON: '삭제하기',
DELETE_BUTTON_TYPE: 'destructive',
POST_TITLE: '작성을 취소하시고 나가시겠습니까?',
POST_MESSAGE: '이 페이지에서 나가시면 저장이 되지 않아요 🥺',
POST_BUTTON: '나가기',
POST_BUTTON_TYPE: 'destructive',
EDIT_TITLE: '수정을 취소하시고 나가시겠습니까?',
EDIT_MESSAGE: '이 페이지에서 나가시면 반영이 되지 않아요 🥺',
EDIT_BUTTON: '나가기',
EDIT_BUTTON_TYPE: 'destructive',
} as const;
type AlertType = 'DELETE' | 'POST' | 'EDIT';
function alertHandler(type: AlertType, onPress: () => void) {
Alert.alert(alertMessage[`${type}_TITLE`], alertMessage[`${type}_MESSAGE`], [
{
text: alertMessage[`${type}_BUTTON`],
style: alertMessage[`${type}_BUTTON_TYPE`],
onPress: onPress,
},
{
text: '취소',
style: 'cancel',
},
]);
}
이런식으로 타입을 지정하고, 해당 타입의 값에 따라 객체에 접근할 수 있도록 해주면 각 화면에서 사용되는 Title, Message, Button 등을 알맞게 사용할 수 있습니다.
하지만 여기서 문제점이 생깁니다. 어떤 화면에서는 단순한 안내만 필요하여 버튼이 2개일 필요가 없을 경우가 있을 수 있고, 버튼이 3개가 필요할 수 있습니다.
2. 리팩토링
고민을 하다가, Chat-GPT에게 방향을 물어보았을 때, 개인적으로는 너무나도 완벽하게 리팩토링을 해주었습니다.
const alertMessages = {
DELETE: {
TITLE: '정말로 해당 게시글을 삭제하시겠습니까?',
MESSAGE: '삭제 후 데이터복구는 어려워요 🥺',
BUTTON: [
{ text: '삭제하기', style: 'destructive' },
{ text: '취소', style: 'cancel' },
],
},
POST: {
TITLE: '작성을 취소하시고 나가시겠습니까?',
MESSAGE: '이 페이지에서 나가시면 저장이 되지 않아요 🥺',
BUTTON: [
{ text: '나가기', style: 'destructive' },
{ text: '취소', style: 'cancel' },
],
},
EDIT: {
TITLE: '수정을 취소하시고 나가시겠습니까?',
MESSAGE: '이 페이지에서 나가시면 반영이 되지 않아요 🥺',
BUTTON: [
{ text: '나가기', style: 'destructive' },
{ text: '취소', style: 'cancel' },
],
},
DETAIL: {
TITLE: '음악을 찾을 수 없습니다.',
MESSAGE: '음악이 삭제되었거나, 올바르지 않은 요청입니다.',
BUTTON: [{ text: '확인', style: 'default' }],
},
LOGIN: {
TITLE: '로그인이 필요합니다.',
MESSAGE: '음악을 등록하기 위해선 로그인이 필요해요.',
BUTTON: [
{ text: '로그인', style: 'default' },
{ text: '취소', style: 'cancel' },
],
},
} as const;
type AlertMessages = typeof alertMessages;
type AlertType = keyof AlertMessages;
function alertHandler(type: AlertType, onPress: () => void) {
const { TITLE, MESSAGE, BUTTON } = alertMessages[type];
const buttons = BUTTON.map(item => {
return {
...item,
onPress: item.style === 'cancel' ? undefined : onPress,
};
});
Alert.alert(TITLE, MESSAGE, buttons);
}
제가 만들었던 AlertMessages에는 각 타입이 반복되어 선언되어있었습니다. DELETE_TITLE, DELETE_MESSAGES 등.. 해당 내용을 한번 더 묶어 각 타입마다 요소들을 넣어주었고, alertHandler 선언부에서는 조금 더 간단하게 각 Title, Message, Buttons를 불러올 수 있게 되었습니다. 또한, 기존의 button의 style에 따라 onPress의 유무를 지정해주어 버튼에 동작 여부를 지정할 수 있었습니다.
3. 정리
이번 작업을 하면서 느낀 점은, 한번 더 공통적으로 구분지어질 수 있는 것들을 구분을 지어 분류하고, 또한 다양한 기능들을 사용해 나에게 맞도록 커스텀 할 수 있어야 한다고 생각되었습니다. 좀 더 열심히 공부해야할듯..!
'개발일지 > React-Native' 카테고리의 다른 글
[React-Native] Apple Login & 회원탈퇴 (1) | 2025.02.06 |
---|---|
[React-Native] Spotify Search API Android에서 노래 제목이 영어로 나오는 문제 (0) | 2024.11.28 |
[React-Native] 지도에서 마지막 위치를 시작 위치로 사용하기 (2) | 2024.11.15 |
[React-Native] Fabric 모드 전환 시 Metro에 연결이 안되는 문제 (0) | 2024.10.30 |
[React-Native] React-Navigation과 React-native-safe-area-context의 중복 여백 문제 (1) | 2024.10.17 |