티스토리 뷰

(RN으로 출석체크 어플을 만들며 겪었던 에러를 정리한 글입니다. expo 38.0.8 을 사용하였습니다)
앱을 만들다보면 특정 상황에서 앱을 재시작하도록 하고 싶을 때가 생긴다. 구글에 react native restart를 검색해보면 제일 상단에 이를 지원하는 react-native-restart 패키지를 찾을 수 있다.

react-native-restart 패키지

https://www.npmjs.com/package/react-native-restart

링크에 들어가서 살펴보면 사용법이 정말 간단하다.

npm i react-native-restart  

설치 후

import RNRestart from 'react-native-restart'; // Import package from node modules

// Immediately reload the React Native Bundle
RNRestart.Restart();

패키지를 import 하고 해당 모듈의 Restart 함수를 호출하면 된다. 하지만 내 사이드 프로젝트에서는 계속해서 에러가 났다.
expo를 사용해서 개발하다보니 당연히 에러가 나는 거였지만... 당시에는 몰랐습니다 ㅠ

null is not an object 에러

RNRestart 가 정의되어 있지 않아서 나는 에러이다. 그래서 대강 해당 패키지 소스코드를 살펴보았다.

import { NativeModules } from 'react-native';

const { RNRestart } = NativeModules;

type RestartType = {
  Restart(): void;
};

export default RNRestart as RestartType;

위 코드는 react-native-restartindex.ts 전체를 가져온 것이다. 짧고 간단하니 대강 읽어보면 흐름이 이렇다.

react-native 모듈에서 NativeModules를 비구조화 할당하여 가져오고, NativeModules에서 RNRestart를 비구조화 할당해서 가져온다. 그리고 RNRestart에는 void형을 리턴하는 Restart() 함수가 존재해야 한다. 그리고 RNRestart를 export하여 모듈로 쓸 수 있도록 한다

음... 눈에 띄는 건 react-native라는 모듈이다. 보통 여기서 Text, View 등을 꺼내서 써왔으니 여기처럼 똑같이 꺼내서 직접 사용해보았다.

import { NativeModules } from 'react-native';
const { RNRestart } = NativeModules;
...
    const confirmOnPress = () => {
    RNRestart.Restart();
  };
...

위처럼 코드를 작성해서 써보았지만

같은 에러가 났다. 원인은 RNRestart 가 정의되어 있지 않아서 나는 에러다(null이 뜨니깐). react-native -> NativeModules -> RNRestart 의 흐름을 고려했을 때, NativeModules에서 RNRestart가 빠져있다는 의미다. 그래서 NativeModules 를 찾아보았다.

NativeModules

https://reactnative.dev/docs/native-modules-ios
간단히 말해서, React Native에서 지원하지 않는 네이티브한 기능들(iOS, Android 네이티브)을 Javascript로 재작성할 것 없이 이미 작성된 코드를 그대로 사용하고 싶을 때 혹은 재작성할 수 없어서 각각 따로 개발해야할 때 이 모듈을 사용한다. 또 리액트 네이티브는 크로스플랫폼 라이브러리니깐 특정 부분에서 네이티브보다 성능이 떨어질 수 있는데 이를 최적화, 성능향상하기 위해서 네이티브로 코드를 작성할 수도 있고 이를 지원하는 것이 바로 이 모듈이다.

내 사이드 프로젝트는 하이 퍼포먼스가 필요하지 않고, 네이티브만의 기능을 따로 사용하지 않기에(재시작을 제외하곤) 더이상 파고들지 않기로 했다. 하지만 앱 재시작은 여전히 필요했다.

expo-updates

생각해보니 내 사이드프로젝트는 expo를 사용해서 개발 중이었다. 그래서 react-native-restart 패키지가 작동이 잘 안되는 것은 당연했다. 단순히 npm install 하고 끝내는 것이 아닌 네이티브 코드를 RN에 링킹해줘야하는 작업이 더 있었다. 빨리 MVP모델을 개발해서 테스트를 해야하는데 개발 병목이 일어서 더 간단하게 앱 재시작을 구현할 방법을 찾다가 expo-updates 패키지를 찾을 수 있었다.

전에는 expo 패키지에 포함되어 있던 것 같았는데 빠진 것 같다. 그래서 사용하기 위해서 설치해주어야 한다.

expo install expo-updates

사용법은 정~말 간단하다. expo-updatesreloadAsync() 함수를 호출하면 앱이 재시작된다. 그래서 아예 Restart.js라는 모듈로 만들어서 사용했다. 코드는 아래와 같다.

// Restart.js
import * as Update from "expo-updates";
export default () => Update.reloadAsync();

이제 앱을 재시작하고 싶은 곳에서 모듈을 임포트해주고 (import Restart from "Restart.js"), 함수를 호출해주면 된다(Restart()). expo를 사용하여 개발을 진행했기 때문에 앱 재시작과 같이 네이티브한 지식이 필요한 곳에서도 별다른 지식 없이 간단하게 앱을 재시작할 수 있게 되었다.
(Update.reloadAsync() 함수에 대해 자세히 알고 싶다면 아래 링크로 들어가서 더 읽어보는 것을 추천해요)
https://docs.expo.io/versions/latest/sdk/updates/

정리

앱 재시작을 위해 react-native-restart를 사용해보고 안되어서 찾다보니 NativeModules에 대해서도 알게 되었다. 크로스플랫폼으로 앱을 개발하다보면 성능최적화를 위해 일부분을 네이티브 코드로 작성한다는 것을 들었는데 이와 관련된 내용을 맛보기로 접한 것 같다.
하지만 기술보다 사용자 경험을 우선시하는 걸 잊지말자. 개발 중인 출석체크 사이드 프로젝트는 MVP모델로 출시해보고 피드백을 받아가며 앱을 수정해야하기 때문에 expo의 기능들을 적극 활용하기로 했고 앱 재시작을 위해서 expo-updates 패키지를 사용하였다.
결론: expo 짱.

댓글