본문 바로가기
  • 바쁜 일상 속 작은 기억
React Native

[React Native] react-native 안드로이드 뒤로가기 BackHandler

by hellomingure 2022. 12. 28.

리액트네이티브의 장점, 안드로이드와 IOS 둘 다 동시에 개발이 가능하다는 점! 

그러나 안드로이드와 IOS의 큰 차이점이 있으니, 그것은 바로 하단에 뒤로가기 버튼!

IOS와 다르게 안드로이드는 하단에 네비게이션바가 있어 자체적으로 뒤로가기 버튼을 누를 수 있다. 

출처 : https://www.google.com/url?sa=i&url=https%3A%2F%2Fflygoeun.tistory.com%2F15&psig=AOvVaw2jIEAEPNM3toxykVnzx0xC&ust=1672321488536000&source=images&cd=vfe&ved=0CA0QjRxqFwoTCMDy0pS5nPwCFQAAAAAdAAAAABAH

그렇다는 것은, 아래 이미지와 같이 우리가 만들려는 RN 앱에서 사용할 헤더 뒤로가기 버튼에 특정 이벤트가 걸려있는 경우에는 헤더 뒤로가기를 누르는게 아닌, 안드로이드 자체 뒤로가기를 누를때 뒤로가는 액션에 대한 특정 이벤트가 적용이 안된다.

 

예를들어, 헤더 < 뒤로가기를 누르면 '회원가입을 그만두시겠습니까?'와 같은 안내 모달창이 뜬다고 가정해보자.

헤더 < 아이콘 뒤로가기를 누르면 안내 모달창이 뜨겠지만, 안드로이드에서 자체 네비게이션 바 뒤로가기를 하면 안내 모달창이 뜨지 않고 그냥 바로 뒤로가기가 실행되어버린다는 의미이다. 

 

상단 헤더 < 뒤로가기 버튼 예시

이 때 사용하는것이, BackHandler 

https://reactnative.dev/docs/backhandler

 

BackHandler · React Native

The Backhandler API detects hardware button presses for back navigation, lets you register event listeners for the system's back action, and lets you control how your application responds. It is Android-only.

reactnative.dev

사용 방법은 간단하다. 

우선, 공식문서에 나와있는 사용방식이다.

BackHandler.addEventListener('hardwareBackPress', function () {

  if (!this.onMainScreen()) { //뒤로가기 이벤트 실행 조건
    this.goBack(); //발생하고싶은 이벤트
    /**
     * return true 이면 이벤트가 버블링되지 않으며, 다른 뒤로가기 액션이 실행되지 않는다.
     */
    return true;
  }
  /**
   * return false 이면, 이벤트가 버블링되며, 다른 이벤트 리스너 혹은 시스템 기본 뒤로가기가 실행된다.
   */
  return false;
});

위 내용을 바탕으로 적용한 코드이다

import React, { useEffect, useState, useLayoutEffect } from 'react';
import { BackHandler, Platform } from 'react-native';
import { useIsFocused } from '@react-navigation/native';
.
.

const useRegistScreen = () => {
    const isFoucsed = useIsFocused();
    const [openModal, setOpenModal]=useState<boolean>(false);

    const goBack = () => {
      if (openModal === false) {
        setOpenModal(true);
        return true; //true면 기존 뒤로가기 명령을 무시하게 된다(뒤로가기 버튼이 작동하지 않게 된다). 
      }

      return false; //기본적인 안드로이드 뒤로가기 명령 그대로 보냄
    };
    
    useLayoutEffect(() => {
        navigation.setOptions({
          headerLeft: () => <HeaderLeft title='회원가입' onPress={goBack} />,

          headerTitle: '',
          headerTitleAlign: 'center',
        });
      }, []);
  

    useEffect(() => {
        if (isFoucsed) {
          BackHandler.addEventListener('hardwareBackPress', goBack);
        } else {
          BackHandler.removeEventListener('hardwareBackPress', goBack);
        }

        return () => {
          BackHandler.removeEventListener('hardwareBackPress', goBack);
        };
      }, [isFoucsed]);
      
    .
    .
    .
  
  }
  
 //그 외 불필요한 코드 생략, 통으로 복붙시 작동안함주의

 

포인트는 위 코드에 주석 달린 goBack 함수의 return true와 false 의 경우 어떻게 작동하는가, 그리고 useEffect 부분 코드이다. 그리고, 헤더 뒤로가기 버튼에 붙은 onPress 에 goBack 이 동일하게 들어가있는 것.

 

여기서, isFocused를 쓰는 이유!

React native 특성 상, A screen에서 B screen으로 이동 후 다시 A screen으로 돌아왔을 때, A Screen에서 실행됐던 이벤트들이 다시 실행되지 않는다.

 

BackHandler 이벤트의 경우, 항상 이 이벤트가 걸려있는 스크린은 몇번을 다시 들어와도 해당 이벤트는 계속 작동되어야 하기에 isFocused를 이용해서 BackHandler 이벤트를 다시 사용할 수 있게 재 랜더링 하는것이다. 

 

useIsFocused 에 대해서는 다음 포스팅에서 다뤄보도록 하겠다.