[React Native] addListener를 활용한 login status 에 따른 rendering
React Native를 할 때 가장 어려웠던 점을 꼽으라면,
this.props.navigation.navigate(‘이동하고자하는 Component이름’)을 Handling하는 것이었어요 :(
이번 포스트에서는 배달의 민족 클로닝앱을 하는 과정에서 login 전 후에 따라서 My배민 페이지를 다르게 Render하는 방법에 대해서 정리해보고자 해요.
Summary
React Native에서 page를 navigate하는 것은 stack 구조로 진행이 되기 때문에 goBack()이든 this.props.navigation.navigate(‘원하는페이지’)이든 이미 didMount된 상태의 페이지가 불려지고, 다시 componentDidMount가 되지 않습니다.
이럴 땐 this.props.navigation.addListener()를 활용하면 됩니다.
제가 원했던 것은 아래와 같았습니다. 여기서 3번이 제대로 구현이 되지 않았어요.
MyPageScreen
에서로그인
버튼을 클릭하면, 로그인 화면(<Login>)이 뜬다.- 아이디, 비밀번호를 입력해서 로그인이 성공하면,
AsyncStorage.setItem('isLogin', JSON.stringify(ture))
값을 설정해주고,this.props.navigation.navigate('MyPageScreen')
으로 MyPageScreen으로 화면을 이동시킨다. MyPageScreen
에는 더이상로그인
버튼이 없고, 로그인 상태를AsyncStorage.getItem('isLogin')
으로 확인여this.state._isLogin
에 반영해준 후 isLogin이true
일 경우 유저의 정보가 보이는 화면을 보여준다.
import React from 'react';
import {
View,
AsyncStorage
} from 'react-native';
import Login from './Login';
import IfUserLoggedIn from '../MyPageScreen/IfUserLoggedIn';class MyPageScreen extends React.Component { state = {
_isLogin: false
}; componentDidMount() {
this.checkLoginStatus();
} // componentDitMount 될 때 AsyncStorage에서 login상태값을 체크한다.
// 참고로 로그인에 성공하면
// AsyncStorage.setItem으로 isLogin 값을 'true'로 바꿔준다.
checkLoginStatus = () => {
AsyncStorage.getItem('isLogin', (err, result) => {
this.setState({ _isLogin: JSON.parse(result) });
});
}; render() {
return (
<View>
{_isLogin
? <IfUserLoggedIn /> // 로그인해서 유저정보가 출력됨.
: <Login> // 로그인 안했음. 로그인 버튼이 출력됨.
}
</View>
);
}}
저는 React Native에서 페이지를 이동시킬 때는 React-Navigation을 사용했어요. 문제는 this.props.navigation.navigate를 이용할 때는 Stack구조로 쌓여있는 상태에서 그 페이지가 불려오는 방식이기 때문에 그렇습니다.
공식문서를 참고해볼까요?
Example scenarioConsider a stack navigator with screens A and B. After navigating to A, its componentDidMount is called. When pushing B, its componentDidMount is also called, but A remains mounted on the stack and its componentWillUnmount is therefore not called. When going back from B to A, componentWillUnmount of B is called, but componentDidMount of A is not because A remained mounted the whole time.stack navigator로 된 화면A와 화면B가 있다고 해보자. A로 이동하면 componentDidMount가 호출됩니다. 그리고 B로 이동하면 B의 componentDidMount도 역시 호출됩니다. 하지만 A는 stack에 mount된 상태로 남아있기 때문에 A의 componentWillUnmount는 호출되지 않습니다. 이제 B에서 A로 돌아가면, B의 componentWillUnmount는 호출되지만 A의 componentDidMount는 호출되지 않습니다. A는 계속해서 mount된 상태로 stack에 남아있었기 때문입니다.출처: https://reactnavigation.org/docs/en/navigation-lifecycle.html
결론은 React navigation을 이용해서 페이지를 옮길 때마다 componentDidMount가 된다는 뜻이 아니라는 것이니까, 어떠한 방법을 잘 찾아서 페이지가 옮겨지면 다시 componentDidMount가 될 수 있도록 만들어주면 되겠네요!
import React from 'react';
import {
View,
AsyncStorage
} from 'react-native';
import Login from './Login';
import IfUserLoggedIn from '../MyPageScreen/IfUserLoggedIn';class MyPageScreen extends React.Component { state = {
_isLogin: false
}; componentDidMount() {
this.onLoad();
} onLoad = () => {
this.props.navigation.addListener('willFocus', () => {
this.checkLoginStatus();
});
}; checkLoginStatus = () => {
AsyncStorage.getItem('isLogin', (err, result) => {
this.setState({ _isLogin: JSON.parse(result) });
});
}; render() {
return (
<View>
{_isLogin
? <IfUserLoggedIn /> // 로그인해서 유저정보가 출력됨.
: <Login> // 로그인 안했음. 로그인 버튼이 출력됨.
}
</View>
);
}}
저도 인터넷에서 찾아보다가 알게되었는데, 제가 진행했던 방식을 위와 같습니다. addListener
중에서 willFocus
라는 속성을 사용해서 계속해서 MyPageScreen
페이지가 불릴 때마다 로그인 상태를 체크할 수 있게 되었어요 :)
willFocus
는 그 페이지로 이동하기 직전에 제가 설정한 내용(함수)를 실행시켜주는 React navigation lifecycle event 중 하나입니다. 다른 life cycle도 궁금하시다면 여기를 클릭해서 추가적으로 확인하실 수 있어요!