react-navigation升级3.x 问题解决方案

背景

  • 最近把之前的RN项目更新了,react-native升级到了0.58,react-navigation升级到了3.3.0。
  • 我们项目结构是TabNavigation,有A/B/C三个Tab,根据用户的权限来决定展示几个Tab,会有四种情况,ABC、AC、BC、C(C是一直存在的)。用createAppContainer创建了四个TabNavigation

升级

  • 按照旧版本的实现,创建三个StackNavigator,按照权限再创建四个TabNavigator,根据权限来决定展示哪个。新版本升级后,统一使用createXXXNavigator生成,然后通过createAppContainer导出才行。

遇到的问题

  • 修改为新版本的写法后,发现进入二级页面tabbar不隐藏了,之前的参数不管用了。查阅文档后,官方给出了建议的写法:把TabNavigator当做StackNavigator的一部分,push时二级页面整个盖到TabNavigator上。reactnavigation.org/docs/en/nav…
  • 之前跳转二级页面时写的是this.props.navigation.navigate('XXX'),按照上面官方建议修改之后发现不好使了…原因是this.props.navigation获取到的是当前页面的navigation,但是我们外面包了一层TabNavigator,此时应该用TabNavigator的navigation去navigate('XXX')。比如页面A和页面B,在TabC上,在页面A上navigate('D'),但是页面A的StackNavigator里没有D哇,并且我们要把Tab盖住哇,所以要用TabC的this.props.navigation去navigate('D')才可以。如果页面A的StackNavigator里有D,navigate时tabbar还会在,隐藏不了,就又回到了上一个问题。我的解决办法是:在跳转二级页面时发个通知,用TabC接收,然后再TabC里进行页面跳转。有点笨,但是想不到其它好办法了…
  • 还有就是安卓物理返回键的问题。这个问题真的很尴尬啊,在第一个Tab进二级页面,按返回键可以很棒的返回,然而在第二个和第三个Tab进二级页面后,按一下返回没反应,按两下就直接到第一个Tab了!!!Oh my god~~~~然后找解决方案,官方文档给出了reactnavigation.org/docs/en/cus…,我是想在一个地方写然后全局都可用,来来回试了很多次也没弄好,只能每个页面都写了一次,具体实现看下面的代码。

具体实现

  1. 我们项目结构是TabNavigation,有A/B/C三个Tab,根据用户的权限来决定展示几个Tab,会有四种情况,ABC、AC、BC、C(C是一直存在的)。用createAppContainer创建了四个TabNavigation
const ABCTabbar = createBottomTabNavigator({
    'ANav': {screen: ANav,},
    'BNav': {screen: BNav,},
    'CNav': {screen: CNav,},
});
const ACTabbar = createBottomTabNavigator({
    'ANav': {screen: ANav,},
    'CNav': {screen: CNav,},
});
const BCTabbar = createBottomTabNavigator({
    'BNav': {screen: BNav,},
    'CNav': {screen: CNav,},
});
const CTabbar = createBottomTabNavigator({
    'CNav': {screen: CNav,},
});

const ABCTabNavigator = createAppContainer(ABCTabbar);
const ACTabNavigator = createAppContainer(ACTabbar);
const BCTabNavigator = createAppContainer(BCTabbar);
const CTabNavigator = createAppContainer(CTabbar);
export { ABCTabNavigator, ACTabNavigator, BCTabNavigator, CTabNavigator };
复制代码
  1. 新建MainNavigation.js,在这个文件里判断用户有哪些权限,然后展示相应的TabNavigator
class MainNav extends Component {
	render() {
	  if (this.state.permission === 'ABC') {
	    return (<ABCTabNavigator/>);
	  } else if (this.state.permission == 'AC') {
	    return (<ACTabNavigator/>);
	  } else if (this.state.permission == 'BC') {
	    return (<BCTabNavigator/>);
	  } else {
	    return (<CTabNavigator/>);
	  }
	}
}
复制代码
  1. 在MainNavigation.js里,生成一个MainNavigation,在入口render里配置成就OK了
const Main = createStackNavigator({
    MainNav: {screen: MainNav},
    DPage: {screen: DPage},
});
const MainNavigation = createAppContainer(Main);
export default MainNavigation;
复制代码
  1. 安卓物理返回键问题。从网上找了个工具类AndroidBackAction.js,修改了一下
import {BackHandler} from 'react-native';

const handleAndroidBackButton = callback => {
  BackHandler.addEventListener('hardwareBackPress', callback);
};

const removeAndroidBackButtonHandler = (callback) => {
  BackHandler.removeEventListener('hardwareBackPress', callback);
}

export {handleAndroidBackButton, removeAndroidBackButtonHandler};
复制代码

页面上的实现:

import {handleAndroidBackButton, removeAndroidBackButtonHandler} from '../../Util/AndroidBackAction.js'; 	// 你自己的路径

export default class D extends Component {

    constructor(props) {
        super(props);
        handleAndroidBackButton(this.onBackAndroid);	// 一定要在这里写
    }

    componentWillUnmount() {
        removeAndroidBackButtonHandler(this.onBackAndroid);	// 一定要在这里写
    }

    onBackAndroid = () => {
        this.props.navigation.goBack();
        return true;
    };
}

复制代码

还有个按两下退出应用的,我是写在了入口的地方(就配置的地方),监听的方式是一样的,就是onBackAndroid实现不一样

onBackAndroid = () => {
    if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
        //最近2秒内按过back键,可以退出应用。
        return false;
    }
    this.lastBackPressed = Date.now();
    ToastAndroid.show('再按返回退出应用', ToastAndroid.SHORT);
    return true;
};
复制代码

好啦,大功告成~~~

结束~撒花~~~

猜你喜欢

转载自juejin.im/post/5c99c983e51d45620c0f3652