首页 > 解决方案 > 如何禁用默认 BackHandler 而不会在单个场景中覆盖它?

问题描述

所以这是我正在使用的路线:

<Router>
                <Scene key="root" hideNavBar>
                    <Stack key="Auth" initial={!this.state.isLoggedIn}>
                        <Scene key="Login" hideNavBar component={Login} title="Login" />
                    </Stack>
                    <Stack key="Main" initial={this.state.isLoggedIn}>
                        <Scene drawer key="NavDrawer" hideNavBar contentComponent={() => <NavDrawer username={this.state.userName} />} type={ActionConst.REPLACE} panHandlers={null}>
                            <Scene key="homeTab" navBar={() => <PageHeader title='Home' />} drawerLockMode={'locked-closed'}>
                                <Scene tabs={true} tabBarComponent={ScrollableTabBar} tabBarPosition='top' lazy={true}>
                                    <Scene key="Home" hideNavBar component={Home} title={"Home"} name='Home'/>
                                </Scene>
                                <Scene key="itemDescription" hideNavBar component={itemDescription} title="Item Description" back />
                            </Scene>
                            <Scene key="helpTab" navBar={() => <PageHeader title='Help' />} title="Help" drawerLockMode={'locked-closed'}>
                                <Scene>
                                    <Scene key="Help" hideNavBar component={Help} title={"Help"} />
                                </Scene>
                            </Scene>
                            <Scene key="settingTab" navBar={() => <PageHeader title='Settings' />} title="Settings" drawerLockMode={'locked-closed'}>
                                <Scene>
                                    <Scene key="Setting" hideNavBar component={Setting} title={"Setting"} />
                                </Scene>
                            </Scene>
                            <Scene key="QRTab" navBar={() => <PageHeader title='QR Scanner' />} title="QR" drawerLockMode={'locked-closed'}>
                                <Scene>
                                    <Scene key="QRScanner" hideNavBar component={QRScanner} title={"QR Scanner"} />
                                </Scene>
                            </Scene>
                        </Scene>
                    </Stack>
                </Scene>
            </Router>

这是我的 BackHandler NavDrawer

handleBackButton() {
        if (Actions.currentScene === '_Home')
        this.onSignOut()
    else if (this.state.currentTab !== 'Home') {
        this.setState({ currentTab: 'Home' })
        Actions.homeTab();
    }
    else if (Actions.currentScene === 'Login')
    {
        BackHandler.exitApp();
    }
    else{
        Actions.pop();
    }
    return true;
}

componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}

componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress');
}

似乎 RNRF 抽屉已经为抽屉下任何新堆叠的场景实现了默认的 BackHandler,默认行为为Actions.pop().

此时,所有逻辑场景移动都按预期工作,但是,由于调用了默认 BackHandler 并且只是Actions.pop()返回 Home,选项卡突出显示不会移回 Home,因为 setState({currentTab:'Home'} ) 从未被执行。

关于如何禁用默认处理程序或在不向抽屉中的每个子场景添加单独的 BackHandler 的情况下执行解决方法的任何想法?

更新:原来这个问题只发生在我自动登录时(即跳过Auth堆栈并直接进入Main堆栈),似乎在重新加载和componentWillUnmountcomponentDidMount不被调用之间出现问题,并且以前重新加载的 BackHandlers 以某种方式发生冲突。

因为如果我尝试这种情况:

login --> Setting/Help/QR tab --> hardware back to Home它不会导致问题

但如果我这样做:

autoLogin(login using stored token) --> Setting/Help/QR tab --> hardware back to Home默认的 BackHandler 将被调用,但如果我再次按下,所需的 BackHandler 将被调用并且我已注销,然后如果我再次尝试登录,一切正常!

更新2:

我现在可以确认问题在于热重新加载,当应用程序重新加载时,componentWillUnmount永远不会被调用,并且当它被加载回来时,componentDidMount会再次被调用,现在我们有 2 个 BackHandlers 处理相同的事件(我不知道他们应该如何在这种情况下表现,但这会导致使用处理程序Actions.pop()而不是我定义的处理程序)。

这就是为什么当我注销(并componentWillUnmount调用并删除 BackHandler)并再次登录(然后通过 将新的 BackHandler 加载到干净的状态componentDidMount)时,一切正常。

现在我的新问题是,如果没有任何热重载并且用户只是关闭应用程序并再次打开它(当应用程序实际安装时没有像现在这样通过 expo 加载),这会导致问题吗?

标签: reactjsreact-nativenavigation-drawerreact-navigationreact-native-router-flux

解决方案


在你的 BackHandler 事件监听器中试试这个。请确保将其放在根组件中

let routeName = this.props.navigation.state.routeName // If you're using react navigation
let routeName = Actions.currentScene // If you're using router flux

BackHandler.addEventListener('hardwareBackPress', function() {

  if (routeName !== "Home") {
    this.props.navigation.goBack() // or create go back custom function 
    Actions.pop() // If your're using router flux
    return true;
  }
  return false;
});

推荐阅读