개발일지

[React-Native] 지도에서 마지막 위치를 시작 위치로 사용하기 본문

개발일지/React-Native

[React-Native] 지도에서 마지막 위치를 시작 위치로 사용하기

Seobe95 2024. 11. 15. 02:06

포트폴리오를 위한 프로젝트를 진행 중인데, 메인 화면에서 지도뷰를 사용하고 있습니다. 

 

앱을 껐다가 켰을 때 다른 위치가 아닌, 사용자가 마지막으로 보고 있던 위치를 보여주는 게 사용자에게 더욱 편리할 것이라 생각되어 해당 기능을 추가하게 되었습니다!

 

들어가기에 앞서, 저는 react-native-naver-map을 이용하여 지도뷰를 보여주고, react-native-encrypted-storage를 통해 다양한 값들을 기기에 저장하고 있습니다.

 

1. 앱이 어떤 상태인지 확인하기

먼저 해야할 것은 앱이 켜져 있는지, 아니면 백그라운드에 있는지를 확인하는 것입니다. 이를 AppState를 사용해서 확인할 수 있는데요.

사용자의 기기에 앱이 켜져있는지, 꺼져있는지를 확인하기 위한 훅을 만들었습니다.

function useAppState() {
  const [isComeback, setIsComeback] = useState<boolean | null>(null);
  const appState = useRef(AppState.currentState);

  useEffect(() => {
    const appStateListener = AppState.addEventListener(
      'change',
      nextAppState => {
        if (appState.current.match(/active/) && nextAppState === 'background') {
          setIsComeback(false);
        }
        if (
          appState.current.match(/background|inactive/) &&
          nextAppState === 'active'
        ) {
          setIsComeback(true);
        }
        appState.current = nextAppState;
      },
    );

    return () => appStateListener.remove();
  }, []);

  return { isComeback };
}

export default useAppState;

 

해당 훅은 React-Native의 문서에도 나와있으니 참고해주세요.

 

isComeback을 사용해서, 기본 상태일 때는 null, 나간 경우에는 false, 다시 복귀한 경우에는 true로 나타내 줍니다.

 

2. 마지막 위치를 저장 & 불러오기

마지막 위치를 저장하고 불러오는 훅을 만들었습니다. 

function usePersistLocation() {
  const getPersistLocation = async (): Promise<
    (LatLng & { zoom: number }) | null
  > => {
    const location = await getEncryptedStorage<LatLng & { zoom: number }>(
      storageKeys.LOCATION,
    );
    if (location) {
      return location;
    }
    return null;
  };

  const storeCurrentLocation = async (location: LatLng & { zoom: number }) => {
    try {
      await storeEncryptedStorage(storageKeys.LOCATION, location);
    } catch (err) {
      console.error(err);
    }
  };

  return {
    getPersistLocation,
    storeCurrentLocation,
  };
}

export default usePersistLocation;

 

해당 hook을 통해서, 스토리지에 현재 위치를 저장하고, 불러올 수 있는 기능을 만들었습니다. zoom이 추가되어 있는 것은 사용자의 위치뿐만이 아니라 zoom의 값도 함께 저장하기 위해서 넣어놓았습니다.

 

불러오는 값이 없을 경우 기본적으로 설정된 좌표로 이동할 수 있도록 null을 리턴해줍니다.

 

3. 지도에 적용하기

지도에 적용하기 위해 새로운 hook을 만들어 줍니다. 사실 2번과 새로운 hook을 합쳐도 되지 않을까 싶었는데, 생각해 보니 따로 구분 지어 관리하는 것이 코드를 보기도 편하고, 각각 하나의 역할만 맡는다고 생각되어 나누게 되었습니다.

function useLocation() {
  const mapRef = useRef<NaverMapViewRef>(null);
  const [userLocation, setUserLocation] = useState<LatLng & { zoom: number }>({
    // 기본값: 서울시청
    latitude: 37.5665851,
    longitude: 126.9782038,
    zoom: 14,
  });
  const { getPersistLocation, storeCurrentLocation } = usePersistLocation();
  const { isComeback } = useAppState();

  useEffect(() => {
    async function handlePersistLocation() {
      switch (isComeback) {
        case false:
          storeCurrentLocation(userLocation);
          break;
        default:
          const persistLocation = await getPersistLocation();
          if (persistLocation !== null) {
            mapRef.current?.animateCameraTo(persistLocation);
          }
          break;
      }
    }
    handlePersistLocation();
  }, [isComeback]);

  return {
    mapRef,
    userLocation,
    setUserLocation,
  };
}

export default useLocation;

 

이 훅에서 앱의 상태값을 관리하는 useAppState, 위치를 저장하고 불러오는 usePersistLocation을 사용합니다.

 

useAppStateisComeback의 값이 변경될 때마다 handlePersistLocation을 실행하여 사용자가 앱을 사용하지 않거나 꺼버린 경우 현재 위치를 저장하고, 복귀 혹은 재시작 시 불러오도록 합니다. 스토리지에서 값을 성공적으로 가져올 경우 mapRef를 사용하여 기본 위치에서 저장된 마지막 위치로 이동하도록 만들어 줍니다.

 

이렇게 3가지의 훅을 만들어 하나의 기능을 만들어 보았습니다. React에서는 특히나 hook을 이용하여 개발하는 경우가 많은데, 각 hook마다 너무 많은 기능을 담당하기보다는 작은 단위로 나누어 조합하여 사용하는 것이 사용하기에는 조금 편할 것 같단 생각이 들었지만, 반대로 규모가 커지면 새로 투입되는 사람이 보기에 조금은 힘들지 않을까..? 하는 생각이 들었습니다.