리액트 네비게이션 screen focus 문제

2020. 7. 27. 02:32React

리액트 네이티브로 프로젝트를 진행중인데, 화면 라우팅 용으로 리액트 네비게이션을 사용중이다.

단순 라우팅 이외에도 params를 화면간에 넘겨줄 수 있는 게 참 편리하다고 생각했고, 그 특징을 적극 활용해서 state를 루트 파일까지 끌어올리지 않고 바로바로 넘겨주며 사용하고 있다. (추후 리덕스로 리팩토링 예정이다.)

 

오늘도 navigation.navigate로 다음 페이지로 넘어가게 해주고, 동시에 params로 변수 몇 가지를 넘기는 부분을 작업했고, 그 후 넘어간 뒤의 스크린(넘어온 뒤의 스크린의 이전 스크린이다.) 에서 params로 받아 온 변수들을 여러 차례에 걸쳐서 합친 뒤 또 다른 스크린으로 넘겨주어야 했다.

 

그래서 대강 화면별 이동하는 데이터의 흐름은 아래와 같았다. (1, 2, 3번 스크린은 하나의 스택 네비게이터로 묶여 있다.)

 

1번 스크린 -> 2번 스크린 -> 3번 스크린 -> 2번 스크린 -> 홈 화면

 

 

처음에는 단순하게 2번 스크린에서 useEffect로 화면이 렌더링 되자마자 받아온 데이터를 바로바로 state에 넣어 주는 것을 상상하고 그대로 구현했는데, 잘 되지 않았다.

 

그러다 리액트 네비게이션 공식 문서를 읽었는데, 네비게이션 라이프사이클이라는 것이 있다고 한다.

 

공식문서: 

https://reactnavigation.org/docs/navigation-lifecycle

 

내가 이해한 바로는, 스택 네비게이션에서는 스크린들이 스택 형태로 쌓이며 화면 이동이 되기 때문에, 이전에 한번 마운팅된 스크린은 스택에 마운팅된 상태로 계속 쌓여 있다고 이해했다. 그래서 위의 예시에서도 2-> 3 -> 2로 넘어갈 때, 2번 스크린이 계속 마운팅된 상태이기 때문에 useEffect가 실행되지 않는다고 추측할 수 있었다.

 

그래서 공식 문서에 솔루션으로 제시된 useFocusEffect, useEffect + focus 이벤트를 모두 시도해 보았지만, 잘 되지 않았다.

 

useFocusEffect, useEffect 안쪽에서 params로 받아온 변수를 찍어보니, 3 -> 2로 이동된 직후에는 undefined가 나왔고, 그 후 다시 refresh하거나 한번 더 3 -> 2로 이동했을 때는 의도한 대로 변수 값이 찍히는 것을 확인할 수 있었다.

 

그래서 이 부분은 비동기 문제라고 판단했고, route.params로 받아오는 변수들도 비동기적으로 들어오는 것이 아닌가 하고 추측했다.

 

결국에는 구글링을 통해 아래의 스택오버플로우 게시물로 해결했다:

https://stackoverflow.com/questions/62389349/react-navigation-mounts-a-screen-then-doesnt-accept-the-new-params-passed-again

 

여기에서는 useIsFocused를 사용했는데, 이전에 사용했다가 실패한 useFocusEffect, useEffect + focus 이벤트와 별다른 차이점을 느끼지는 못했다..

 

정확하게 위의 세가지가 실행되는 시점과, routes.params로 들어오는 값이 들어오는 시점을 알지 못하고, 이들의 정확한 구동 원리를 알지 못해서 그런 것 같은데..

 

 

일단 눈에 보이는 문제는 해결되었지만 추후에 더 알아보려고 블로그 게시물로 남겨 둔다.

당장은 프로젝트.. 가야 할 길이 너무 멀어서..

 

 

 

+) 20/07/28 추가

 

아래처럼 세 방법의 콘솔을 찍어봤다.

// useFocusEffect
useFocusEffect(
    useCallback(() => {
        console.log('useFocusEffect');
    }, [])
);

// useEffect + focus 이벤트
useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
       console.log('focus');
    });
    return unsubscribe;
}, [navigation]);

// useIsFocused
const isFocused = useIsFocused();
useEffect(() => {
   if (isFocused) {
       console.log('isFocused');
    }
}, [isFocused]);

 

실행되는 순서는 위와 같았고, 세 가지의 실행 순서는.. 아무래도 상관이 없는 것 처럼 보인다.

그런데 각 방법 중 두 가지의 함수 내부에서 찍히지 않았던 문제의 route를 함께 찍어봤더니, 한번 페이지에 진입할 때마다 useFocusEffect는 3번~, useEffect + focus 이벤트는 2번, useIsFocused는 1번씩 콘솔에 찍히는 것을 확인할 수 있었다.

여러번 불려 오는 이유를.. 잘 모르겠고, 이것도 더 알아봐야 할 것 같다.

지금 다른 페이지에서 이유를 알 수 없게 인자로 받은 route가 undefiend가 되는 문제가 존재하는데, 이 부분도 비동기적인 문제인지, 다른 문제인지 더 알아봐야 할 것 같다..

 

 

 

+) 20/08/13 추가

관련 내용으로 기술 발표를 진행했다.

docs.google.com/presentation/d/1Vn2O3hhYdBroVXxDifCyVA848vLxahrnBdTBXlZsQrI/edit?usp=sharing

 

 

'React' 카테고리의 다른 글

React Naitive, Redux로 미니 투두앱 만들기  (0) 2020.07.19
React Hooks  (0) 2020.07.02
hash router & browser router  (0) 2020.06.05
React로 Twittler 구현해보기  (0) 2020.04.17