[RN] useFocusEffect의 행동양식

devAnderson·2022년 7월 25일
2

react-native

목록 보기
1/6

1. 작성 계기

최근 React native 앱 관련 유지보수를 위해 이슈를 해결하던 도중, 탭의 이동에서 미세한 동작 에러가 발생하는 것을 확인하고 이를 해결하기 위해 코드를 살펴보고 있었다.

그러던 도중, useFocusEffect라는 것을 알게 되었고 이 훅의 행동 양식에 대해서 작성하여 볼 만한 일이 있어서 적게 되었다.

2. useEffect vs useFocusEffect

보수를 위해 코드에서 눈여겨봐야 하는 부분은 아래와 같았다.

  useFocusEffect(
    useCallback(() => {
      onTab(initPageNum)
    }, [initPageNum, onTab]),
  )

React의 관점에서 component가 호출되면서 파싱되어 리턴이 되는 jsx 문법의 내용은 Babel에 의하여 변환되어 React.createElement로 변환된 뒤 호출되는 구조로 되어있다.

즉, component를 간단하게 함수라고 생각하면,
훅은 React 앱에서 호출 순서를 기억시키고 있는 함수객체라고 보면 이해가 쉬울 것이다.

useFocusEffect가 호출될 때 하는 역할은 인자로 받아들이는 값을 화면의 "focus" 이벤트가 발생할 때 호출을 하도록 설계되어 있다.

사실상 focus가 되는 순간 특정 함수가 호출이 되는 것은 동일하므로, 실행되야 하는 함수를 굳이 재평가 할 필요가 없도록 useCallback에 전달하여 React 앱의 전역 환경에 고정시키는 것은 합리적인 절차라고 생각한다.

단, 주의할 점이 있다. useFocusEffect는 기본적으로 스크린이 포커싱이 되었을 때만 실행되는 것이 맞지만, useCallback의 디펜던시가 감지하는 내용의 변동으로 인해 내부 지역 상태가 바뀔 경우 역시 호출된다. 이 점을 정말 주의해야 한다.

useFocusEffect를 사용하기 가장 좋은 부분은 데이터를 서버로부터 패칭을 받는 행위 라고 소개하고 있다.

이 부분을 눈여겨보면 좋다. 그 이유는 후에 나올 것이다.

그런데, 여기서 useFocusEffect의 특징은 스크린이 "focus"가 되었던 순간에 호출이 된다는 점이지, "리랜더링이 되는 순간" 호출이 되는 것은 아니라는 점이다.

이게 무슨 소리냐면,

initPageNum은 스크린에 들어오는 순간 전달되는 값이고, page number은 스크린 컴포넌트 내에 존재하는 상태값이다.

page 값은 useFocusEffect에 의해 발생하는 함수로 업데이트되는데,
이때 useFocusEffect의 Effect 함수는 지역 환경 업데이트 기준을 initPageNum와 onTab에 따라 변경된 뒤 실행이 되는 구조이다.

 useFocusEffect(
    useCallback(() => {
      onTab(initPageNum)
    }, [initPageNum, onTab]),
  )

리엑트는 전달되는 props가 바뀌거나 내부 state 값이 변경되는 등 특정 조건에 따라 리랜더링을 진행한다.

리랜더링이라 함은, 해당 js 함수 코드를 다시 재호출하여 Virtual Dom 내부에 react 객체를 새롭게 업데이트시킨 후 효과적으로 변경점을 랜더링하는 과정을 포함한다.

그래서 사실상, useCallback이 기억하는 함수 내의 지역 변수값(여기서는 initPageNum)은 변경된 상태로 리엑트앱의 전역 환경에서 그 함수 자체가 기억되고 있는 상태이다.

하지만, 여기서 중요한 점은 useFocusEffect는 리랜더링과 상관 없이 해당 스크린이 포커스되는 그 한 순간에만 작동한다는 점이다.

다시금, 위의 내용을 다시 보자면

initPageNum은 첫 포커싱 당시에는 1로 전달받은 상태이다.

따라서 useFocusEffect도 이 지역변수 값을 사용하여서 내부 상태인 page를 업데이트한다.

하지만, 그 이후로 rerendering이 되면서 바뀌게 되는 지역값 initPageNum인 0이 반영되어도 useFocusEffect는 호출되지 않기 때문에 변경점이 적용되지 않는 것이다.

그리고 내부 상태인 page는 첫 initPageNum이 1이었던 것으로 인해 변경되는 값 "1"에서 더이상 변경이 되지 않는 것이다

3.결론

요약하자면 아래와 같다

만약 리랜더링을 포함하여 스크린이 포커싱 되는 순간 모든 변경점이 반영 된 특정한 결과를 랜더링을 진행하고 싶다면 "useEffect"를 사용해야 한다.

만약 스크린이 포커싱이 되는 그 순한 단 한번을 주목하여 필요한 로직, 예를 들어 데이터 패칭과 같은 행위를 한번만 하도록 하고 리 랜더링 마다 실행하고 싶지 않다면 useFocusEffect를 사용하는 편이 좋다.

profile
자라나라 프론트엔드 개발새싹!

1개의 댓글

comment-user-thumbnail
2023년 12월 27일

참 좋은 글 입니다.

답글 달기