지금까지 배운 안드로이드 백버튼 기능과 메모리 누수를 개선하여 리팩토링을 진행해보도록 합시다.
useEffect 내의 return 구문을 활용해 기존 이벤트 리스너를 제거하여 안전성을 높일 수 있습니다.
exitDeviceRoutingForBackSet 함수를 추가하여 안드로이드 백버튼과 종료기능을 연결해줍니다.
import { useEffect, useState } from "react";
import { BackHandler, ToastAndroid } from "react-native";
export const useDeviceRouting2 = (onResponse) => {
const [exitCount, setExitCount] = useState(0);
useEffect(() => {
const backHandler = () => {
if (exitCount >= 1) {
BackHandler.exitApp(); // '뒤로' 버튼을 2번 눌렀으므로 종료
} else {
onResponse({ back: true }); // 웹에 뒤로가기 눌렸다고 알려주기
}
return true; // 안드로이드 백버튼 기본기능 무시하기
};
BackHandler.addEventListener("hardwareBackPress", backHandler);
**return () => {
BackHandler.removeEventListener("hardwareBackPress", backHandler);
};**
}, **[exitCount]**); // exitCount 증가되어 새로운 useEffect가 재실행되면? 기존의 addEventListener 제거해야됨(메모리누수)
**// 09-04-android-back-exit => 안드로이드 백버튼과 종료기능 연결
const exitDeviceRoutingForBackSet = () => {
setExitCount((prev) => prev + 1);
ToastAndroid.show("'뒤로' 버튼을 한번 더 누르면, 앱이 종료됩니다.", ToastAndroid.SHORT); // prettier-ignore
setTimeout(() => setExitCount(0), 2000); // 2초 후 원상복귀
onResponse({
exitDeviceRoutingForBackSet: {
message: "종료시도",
},
});
};**
return {
exitDeviceRoutingForBackSet,
};
};
커스텀 훅 파일을 리팩토링 해보겠습니다.
onRoutingBack 함수를 추가해주면서 종료 대상 페이지와 일반 페이지를 구분해 UX를 개선하고, 불필요한 요청 방지로 성능을 최적화 합니다.
import { FETCH_DEVICE_KEY } from ".";
declare const window: Window & {
ReactNativeWebView: {
postMessage: (message: string) => void;
};
};
export const useDeviceSettingRedirectAndBackExit = () => {
const fetchApp = async ({ query, variables = {} }) => {
const result = await new Promise((resolve) => {
FETCH_DEVICE_KEY[query] = resolve;
window.ReactNativeWebView.postMessage(
JSON.stringify({ query, variables })
);
});
return result;
};
return {
fetchApp,
};
};
import { usePathname, useRouter } from "next/navigation";
import { useDeviceSettingRedirectAndBackExit } from "../09-04-device-setting-redirect-and-back-exit/hook";
const 종료되어야하는페이지들 = [
"/section09/09-04-android-back-exit", // 메인페이지, 시작페이지 등...
// ...
];
export const useRoutingSettingBackExit = () => {
const router = useRouter();
const pathname = usePathname();
const { fetchApp } = useDeviceSettingRedirectAndBackExit();
const onRoutingBack = () => {
// // 1. 종료되어야하는 페이지라면? => 종료요청
const isExitPage = 종료되어야하는페이지들.includes(pathname);
if (isExitPage) return fetchApp({ query: "exitDeviceRoutingForBackSet" });
// // 2. 뒤로가야하는 페이지라면? => 뒤로가기
return router.back();
};
return {
onRoutingBack,
};
};