지금까지 배운 안드로이드 백버튼 기능과 메모리 누수를 개선하여 리팩토링을 진행해보도록 합시다.

mobile apis 폴더내 파일 리팩토링

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,
  };
};

web settings 파일 리팩토링

커스텀 훅 파일을 리팩토링 해보겠습니다.

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,
  };
};