네비게이션 이동에서 렉이 엄청나게 발생한다!

react native로 앱을 만들면서 네비게이터로 expo router를 사용하고 있었다.
그런데 이상하게 특정 페이지로 이동할 때 렉이 매우 심하게 걸리는 것이다.
https://www.reddit.com/r/reactnative/comments/1cxslm7/expo_router_stack_navigation_lags/
찾아보며 발견한 글인데 해당 글에 나오는 영상 정도의 렉이 걸렸다.

원인이 무엇이었을까

당시 생각에 원인이...

  1. 현재 useRoute를 사용하는 것과 컴포넌트를 사용하는 것에서 나오는 차이일까?
    그런데 Link 컴포넌트를 쓰는 방법으로 바꿔도 여전히 문제가 있다.
    생각해보면 컴포넌트를 사용하지 못하는 상황도 있을텐데 네비게이팅 방법에 따라 성능차이가 있다면 진작에 문서에 적혀있거나 스택오버플로에 관련 글이 있었을 것
    +그땐 몰랐는데 지금 적으면서 찾아보니까 useRoute는 이제 쓰지 말라고 한다 ㄷㄷ
    대신 router라는 객체가 있다.
  2. 탭 네비게이션 간 화면 이동엔 렉이 없는데 스택 네비게이션간 이동에는 렉이 생긴다. 스택 네비게이션에 문제가 있는 것일까?
  3. 드롭다운 메뉴 컴포넌트에서 onPress시 화면 이동을 진행하는데 드롭다운 메뉴 컴포넌트에서 렉이 발생하는 것일까?

정도를 생각해보았다.

그리고 보다 정확한 문제 파악을 위해 퍼포먼스를 측정해보려고 했는데....

https://docs.expo.dev/debugging/tools/
https://medium.com/@dhafinraditya35/platform-monitoring-in-expo-react-native-development-8c8c0bbe29f8

이 두개 글을 보고 똑같이 m을 눌러 개발 메뉴를 연 다음 퍼포먼스 모니터를 열었지만...

왜 나는 저렇게 쪼그맣게만 나오는 것인가!

그리고 나중에 안 사실인데 위 상황은 안드로이드 에뮬레이터에서만 발생하는 문제였고 ios 시뮬레이터에서는 위 블로그에서 나오는 것처럼 자세한 정보를 볼 수 있었다.

그리고 한가지 추가로 안 사실은...
expo dev menu에서 연 debugger에는 네트워크탭과 퍼포먼스탭이 있는데 중요한건 둘 다 동작을 안한다... 그래서 전혀 디버깅에 도움이 되지 않는다. 중단점은 잘 찍히고 잘 멈춰준다.

react native dev menu에서 여는 debugger는 react native experimental이라고 적힌 debugger인데,,, 여긴 애초에 네트워크탭이랑 퍼포먼스탭이 없다!! 이런!

그래서 이것 관련해서 expo 디스코드방에 물어봤는데 이번엔 답변이 안달렸다 ㅠㅠ

다른 사람들은 react native에서 성능 측정을 어떻게 하나 찾아보았다.
React Native 로컬에서 성능 측정하기 (Reassure)
pupfluencer 리팩토링2 : React Native Debugger를 통한 성능 측정 이 글에선 performance 탭이 왜 잘 되지?
이건 리액트지만... 리액트 성능 측정 & 개선하기 (feat. memo & React DevTools)

아무튼 최적화를 하려면 성능 측정부터 해야할텐데 산넘어 산인 것 같다.

근데 사실 이번 네이게이션 렉 문제는 expo router문제가 아니었다. 아무리 찾아봐도 expo router가 느리다, 문제있다란 글이 거의 없었어서 슬슬 뭐가 문제인가 고민에 빠질 찰나

멘토님이랑 같이 코드를 보다가 문득 떠오른게 있었다.

현재 우리는 ui kitten이라는 ui 라이브러리를 사용하고 있는데 이걸 사용하기 위해선 루트 컴포넌트를 applicationProvier라는 컴포넌트로 감싸줘야했다. 근데 문득 저 applicationProvider가 루트 파일에만 있는게 아니라 다른 하위 컴포넌트에도 감싸져있던걸 봤던 기억이 떠올랐고 나는 혹시 이것 때문인가? 하고 하위 컴포넌트에서 applicationProvider를 지우니 놀랍게도 렉이 사라졌다.
이름에서 유추하면 ui 스타일링에 필요한 테마라던가 등의 context api인거 같은데 이게 이렇게 심한 렉을 유발할 줄 몰랐다.
근데 context api만으로는 이런 렉이 설명이 안된다.
그래서 깃헙 코드를 좀 보니

export class ApplicationProvider extends React.Component<ApplicationProviderProps, State> {

public state: State = {
  styles: (this.props as EvaBuildtimeProcessingProps).styles,
};

private schemaProcessor: SchemaProcessor = new SchemaProcessor();

constructor(props: ApplicationProviderProps) {
  super(props);

  if (!this.state.styles) {
    const { mapping, customMapping } = this.props as EvaRuntimeProcessingProps;
    this.state.styles = this.createStyles(mapping, customMapping);
  }
}

private createStyles = (mapping: SchemaType, custom: CustomSchemaType): ThemeStyleType => {
  const customizedMapping: SchemaType = merge({}, mapping, custom);
  return this.schemaProcessor.process(customizedMapping);
};

public render(): React.ReactNode {
  return (
    <StyleProvider
      theme={this.props.theme}
      styles={this.state.styles}
    >
      {this.props.children}
    </StyleProvider>
  );
}
}

props로 styles가 없으면 createStyles 함수를 실행해서 런타임에서 스타일을 만든다.
createStyles 함수를 보면 mapping과 custom 객체를 lodash.merge로 합치고 이걸 schemaProcessor.process에 전달하는데...
schemaProcessor는 eva-design/eva에서 임포트하는 함수다.
이 함수까지 찾긴 넘 귀찮아서 여기까지만 보아하니 런타임에서 스타일을 생성하느라 렉이 엄청 걸리는듯!

앱에 회원탈퇴 기능 만들기

이건 문제였던건 아니고 그냥 회원탈퇴 기능을 잘 만들었다!

앱 홍보 활동

글 쓰는 기준 지난주 디스콰이엇 담당이 나라서 글을 작성해서 올렸다!
https://dis.qa/Yy2XZ
근데 아무도 안봐준다 ㅠㅠ

홍보로 미룬이들을 모아서 우리 앱을 홍보해야겠다 싶어서 카카오톡 오픈챗방도 만들었다.
지난주 금욜인가 목욜인가 만들었는데 현재 3일 정도 지났는데 우리 팀 3명에 놀랍게도 2명이 더 들어와 5명이 모여있다... 작지만 소중한 사람들...

ios에서 모든 기능 동작

잘하는 것을 확인했다!
그런데 탈퇴 기능확인하면서 삭제도 했다가 앱을 다시 깔았는데 시뮬레이터에서 또 APNS 토큰이 없다고 에러가 뜬다. 그래서 우선 실기기에서도 이러는지 확인해볼 것이다.

테스트

jest로 로그인 컴포넌트 테스트하는 코드를 아주아주 간단히 작성했었다. gpt와 함께...
당시에 맨날 집오면 피곤해서 블로그에 쓰질 못했는데 내일 테스트 관련 글을 적어봐야겠다.

테스트를 정말 잘 짠다면 문제 원인을 빠르게 파악할 수 있을 것 같다.

  1. 유닛 테스트, 컴포넌트 테스트에서 ui가 정상적으로 나오는지 확인하고,
  2. 의존성을 가지는 컴포넌트들끼리 통합 테스트를 해서 데이터나 매개변수로 인해 문제가 생기는건 아닌지 테스트하고
  3. 마지막으로 e2e 테스트로 데이터를 받아오는 과정, 전송하는 과정에서 생기는 문제는 없는지 확인할 수 있을 듯

이게 아니라면 디버거를 열어서 예상되는 지점에 중단점도 찍어야하고 스텝도 하나씩 눌러봐야 해서 불편할듯

근데 react native 개발하면서 js 디버거 여는 것보다 좀 더 자주 사용하는게
element inspector인데 주로 문제가 서버와 통신 과정에서 잘못되는게 많다보니까 request response를 확인해야하는데 element inspector에 보면 network 탭이 있어서 쉽게 바로바로 확인할 수 있음. 매우 좋음

근데 디버거도 안쓴다면 콘솔 로그를 이곳 저곳에 코드 라인 마다 집어넣어야 해서 매우 불편할듯

근데 콘솔 로그 찍는 것도 에러를 자세히 보거나 비동기 로직에서 에러 생길 때엔 유용한듯
비동기 로직에서 디버거 쓰면 너무 복잡함....

에러바운더리

드뎌 에러바운더리로 에러핸들링을 해보았다. 재시도가 필요하거나 특정 컴포넌트에 에러를 가두고싶을 때 말그대로 바운더리를 만들고 싶은 부분에 에러바운더리로 에러를 처리하면 좋을 것 같다.

앞으로 할 것은 글로벌 에러바운더리도 하나 만들어서 그외 다른 곳에서 발생한 에러는 토스트로 짧게 현재 에러가 발생했다는 것을 사용자에게 알리면 좋을 것 같다.
예전에 에러의 종류와 그에 따른 적절한 핸들링 방법은 무엇인가에 대한 아티클을 읽은 기억이 있는데 다시 찾아봐야할듯

profile
안녕하세요, 반갑습니다.

0개의 댓글