reactjs - 如何禁用默认 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
堆栈),似乎在重新加载和componentWillUnmount
或componentDidMount
不被调用之间出现问题,并且以前重新加载的 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 加载),这会导致问题吗?
解决方案
在你的 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;
});
推荐阅读
- reactjs - 为什么 usePrevious 在第一次渲染时返回 undefined - 反应钩子?
- r - 如何在给定条件下查找分组数据框中的行数
- obiee - OBIEE 11g - 如何从数据表创建交叉表?
- karate - 空手道:从场景大纲中的背景访问变量
- mysql - GRANT 命令在 MySQL 8.0.25 上不起作用
- python - 尽管安装了所需的库(在 ubuntu 上使用 python3),但 Pyautogui 函数 LocateOnScreen 仍然出错。请帮帮我
- python - Manim 社区版,使用 ThreeDAxes 不适合 ThreeDScene 的对象
- javascript - “ReferenceError:未定义命令”
- c# - EF6 更新 DBContext 类以获取新密码
- sql - 使用 REFERENCES 创建两个表