React Navigation 监听不同页面的物理返回键事件
程序员文章站
2022-07-16 15:10:01
...
前言
本文环境基于:
"react-native": "0.60.5"
"react-navigation": "^4.0.0"
"typescript": "^3.6.2"
首次编辑时间:2019.9.19
描述
在对应页面添加如下代码我们就能监听不同页面的返回事件。
backHandler;
componentDidMount() {
this.backHandler = BackHandler.addEventListener(
'hardwareBackPress',
this.onBackButtonPressAndroid, //处理返回事件函数
);
}
componentWillUnmount() {
this.backHandler && this.backHandler.remove('hardwareBackPress');
}
当我们使用react-navigation做路由导航时,createStackNavigator+createBottomTabNavigator使用时监听返回键就会有诸多问题:
- 多个页面有相同的返回事件,需要给每个页面添加返回事件代码,非常的繁琐冗余。
- tabs页面监听返回事件时,虽然只需要给第一个tab添加返回事件代码。但是这样会造成打开的新页面(tabs页面未关闭)也会被监听。
思路
- 在根导航器中统一管理,一般来说是App.js/App.tsx/App.ts。
- 根据路由属性中路由名称routeName,判断处理对应的事件。
根导航器的没有navigation prop怎么办呢?
可以通过ref访问导航器。并将其传递给我们稍后将使用其进行导航的NavigationService。
不能使用withNavigation,因为它只适用被路由导航包装的子组件。
NavigationService使用具体可以查看官方文档Navigating without the navigation prop
根据官方代码,添加了获取路由名称的方法代码如下:
import {NavigationActions} from 'react-navigation';
let navigator;
//ref传值
const setTopLevelNavigator = navigatorRef => {
navigator = navigatorRef;
};
//页面跳转方法
const navigate = (routeName, params = {}) => {
navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
}),
);
};
//页面goBack方法
const goBack = () => {
navigator.dispatch(NavigationActions.back());
};
//获取当前路由
const getCurrentRoute = () => {
let route = navigator.state.nav;
while (route.routes) {
route = route.routes[route.index];
}
return route;
};
//获取当前路由名称
const getCurrentRouteName = () => {
return getCurrentRoute().routeName;
};
export default {
navigate,
setTopLevelNavigator,
getCurrentRoute,
getCurrentRouteName,
goBack,
};
示例
有了以上思路我们来处理以下场景:
登陆页面login成功后,进入Main(包含3个tabs),用户在Login和Main页面点击返回键会提示他是否确认退出程序?其余页面则不处理登陆事件。
Main底部导航栏代码
省略部分配置代码。
// 导航栏定义
const TabNavigator = createBottomTabNavigator(
{
Home: {
screen: Home,
....
},
Bill: {
screen: Bill,
...
},
Mine: {
screen: Mine,
...
},
...
);
export default createAppContainer(TabNavigator);
App根导航器代码
const AppNavigator = createStackNavigator(
{
Start: Start,
Login: Login,
Main: Main, //底部导航栏
Register: Register,
Modify: Modify,
},
...
);
const AppContainer = createAppContainer(AppNavigator);
export default class App extends React.Component {
backHandler;
componentDidMount() {
this.backHandler = BackHandler.addEventListener(
'hardwareBackPress',
this.onBackButtonPressAndroid, //处理返回事件函数
);
}
componentWillUnmount() {
this.backHandler && this.backHandler.remove('hardwareBackPress');
}
onBackButtonPressAndroid = () => {
const routeName = NavigationService.getCurrentRouteName();
if (
//处理Login和三个tabs(Home,Bill,Mine)
routeName === 'Login' ||
routeName === 'Home' ||
routeName === 'Bill' ||
routeName === 'Mine'
) {
CommUtils.showDialog();
return true; //true阻止返回键向下传递
} else {
return false; //不做任何事情,返回键向下传递,系统默认处理
}
};
public render() {
return (
<AppContainer
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
);
}
}