[React Native] react-native-router-flux 연속 Push, Pop 대응
react-native-router-flux 라이브러리를 사용하면서 발생했던 이슈 몇 가지가 있었다.
1. 두 번 이상의 클릭으로 새로운 스크린을 띄우게 되면 그 갯수만큼 스크린이 열림. (2번 누르면 2개 열림)
2. 창 닫기 버튼을 두 번 이상 클릭 했을 때 Actions.pop()이 여러번 호출 되는 증상. (2번 닫기버튼 누르면 2개 스크린이 닫힘)
3. 안드로이드에서 Back 버튼 두 번 누를 때 종료하는 기능
각각을 다음과 같이 해결함!
두 번 이상의 클릭으로 새로운 스크린을 띄우게 되면 그 갯수만큼 스크린이 열리는 증상
actions.js를 생성 후 다음과 같이 push함수를 정의한다. (현재 스크린의 키 값과 비교 후 이미 띄워졌다면 수행하지 않는 코드)
출처 (github.com/aksonov/react-native-router-flux/issues/2228)
import {Actions} from 'react-native-router-flux';
export const push = (destinationScene, props) => {
// console.log('push', destinationScene, Actions.currentScene, props);
if (Actions.currentScene === destinationScene) {
return;
}
return Actions[destinationScene](props);
};
그리고 다음과 같이 사용
import {push} from './actions';
push('HomeScreen', {data: 'data'});
창 닫기 버튼을 두 번 이상 클릭 했을 때 Actions.pop()이 여러번 호출 되는 증상
actions.js에 열릴 때와 마찬가지로 'popScreen'이라는 함수를 하나 만들어주고
export const popScreen = currentSceneName => {
if (Actions.currentScene !== currentSceneName) {
return;
}
return Actions.pop();
};
다음과 같이 현재 스크린의 scene key를 넣어주는 방식으로 사용하면, 두 번 호출이 되지 않는다!
import {popScreen} from './actions';
popScreen('HomeScreen');
안드로이드에서 Back 버튼 두 번 누를 때 종료하는 기능
App.js에 다음과 같이 BackHandler 이벤트를 등록 (Scene key가 HomeScreen이거나 LoginScreen일 때만 handleBackButton이 수행되도록 함)
import {BackHandler} from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.exitApp = false;
BackHandler.addEventListener('hardwareBackPress', () => {
console.log('Actions.currentScene', Actions.currentScene);
switch (Actions.currentScene) {
// HomeScreen과 LoginScreen에서만 백 버튼을 disabled하고, 여기서 이벤트를 처리하도록 하자!!
case 'HomeScreen':
case 'LoginScreen': {
this.handleBackButton();
break;
}
default: {
//noop
}
}
});
}
handleBackButton = () => {
// 2000(2초) 안에 back 버튼을 한번 더 클릭 할 경우 앱 종료
if (this.exitApp === undefined || !this.exitApp) {
ToastAndroid.show('한번 더 누르시면 종료됩니다.', ToastAndroid.SHORT);
this.exitApp = true;
this.timeout = setTimeout(
() => {
this.exitApp = false;
},
2000, // 2초
);
} else {
clearTimeout(this.timeout);
BackHandler.exitApp(); // 앱 종료
}
return true;
};
// 컴포넌트 지워질 때 이벤트도 지워주자
componentWillUnmount(): void {
BackHandler.removeEventListener('hardwareBackPress', () => {});
}
}
그리고 HomeScreen과 LoginScreen에서는 react-native-router-flux의 기본 back버튼 이벤트가 발생하면 안되므로, Scene을 등록해준 코드에서 다음과같이 back버튼 이벤트를 비활성화 해준다
import HomeScreen from './HomeScreen';
import LoginScreen from './LoginScreen';
...
<Router>
<Scene key='root'>
<Scene
key='LoginScreen'
component={LoginScreen}
type={ActionConst.RESET} // 이 줄이 해당 스크린에서 Back버튼 이벤트를 비활성화
/>
<Scene
key='HomeScreen'
component={HomeScreen}
type={ActionConst.RESET} // 이 줄이 해당 스크린에서 Back버튼 이벤트를 비활성화
/>
</Scene>
</Router>
...
그럼 LoginScreen과 HomeScreen에서는 두 번 연속으로 눌러야 종료가 되고, 나머지에서는 일반적인 방식으로 동작한다.