用户注销时如何重置 TabNavigator(从其他屏幕)

Posted

技术标签:

【中文标题】用户注销时如何重置 TabNavigator(从其他屏幕)【英文标题】:How to reset TabNavigator when user logs out (from other screen) 【发布时间】:2018-06-04 10:20:58 【问题描述】:

这是我的项目文件层次结构

RootTabNavigator
    | AuthStackNavigator // I want to go back to this navigator
          | AuthoScreen
    | Welcome Screen
    | MainTabNavigator // I want to reset MainTabNavigator 
          | FeedStacknavigator
                   | Screen A
          | OtherStackNavigatorOne
                   | Screen E
          | OtherStackNavigatorTwo
                   | Screen D
          | MenuStackNavigator 
                   | Menuo <-I'm here and want to reset to 'MainTabNavigator' 
                             and go BACK to 'AuthScreen'
           | Screen B
                   | Screen C

问题

用户在 MenuStackNavigator 和 MainTabNavigator 下的 Menuo 屏幕上。

如果用户没有令牌(当用户注销时),用户将返回到身份验证屏幕。

但同时我想RESET MainTabNavigator。您可以卸载、执行 NavigationActions.init() 或任何您可以执行的操作。我更喜欢 NavigationActions.init()

我只想将 MainTabNavigator 设置为第一次。

代码

如果没有令牌,我会返回身份验证屏幕(这是有效的)

This code if the part of Menuo Screen

componentWillReceiveProps(nextProps) 
    if ( nextProps.token == undefined || _.isNil(nextProps.token) ) 
      const backAction = NavigationActions.back(
        key: null
      )
      nextProps.navigation.dispatch(backAction);
      ...

(问题)我们如何重置 MainTabNavigator 包括子 StackNavigator?

MainTabNavigator.js

export default TabNavigator(
    
        Feed: 
          screen: FeedStacknavigator,
        ,
        OtherOne: 
          screen: OtherStackNavigatorOne,
        
        ...
    , 
        navigationOptions: (navigation) => )
            header: null,
        tabBarIcon: (focused) => ...
        ...
    

可能的解决方案

我也许可以将 MainTabNavigator 从函数更改为类,并在那里处理重置 TabNavigator。 (我不知道)。

这一次,我需要一个具体的工作示例。我一直在阅读文档并申请到我的应用程序,但我无法解决这个问题。

如果有什么不清楚的地方请告诉我。

更新

const RootTabNavigator = TabNavigator (
    Auth: 
      screen: AuthStackNavigator,
    ,
    Welcome: 
      screen: WelcomeScreen,
    ,
    Main: 
      screen: MainTabNavigator,
    ,
  , 
    navigationOptions: () => (
     ...
  
);

export default class RootNavigator extends React.Component 
  componentDidMount() 
    this._notificationSubscription = this._registerForPushNotifications();
  

【问题讨论】:

我认为快速的解决方案是重置 MainNavigator。里面的所有东西都会自动卸载。像登录-> 个人资料-> 注销然后回到登录。这是您要解决的问题吗.. 是的,这正是我想要的。我可以在后退操作后重置吗?如果这可行,我想以此作为答案。您还需要什么信息?? 建议标签使用nativebase,只有StackNavigator。您将对标签有更多的控制权,并且可以轻松地对其进行reset。导航器的深度递归结构会导致问题,您得到的每个答案都可能只是一种解决方法。下次它又会出现更复杂的结构。 每个 StackNavigator 内部都有 nativebase 选项卡(我的项目很大)。是的,下次我会使用原生的 Tabnavigator,但我真的必须依赖 TabNavigator 感谢您的建议。我很感激。带上其他更懂 react-navigation 的朋友。我真的需要快速解决这个问题...... 【参考方案1】:

您需要将导航器初始化为初始状态。你可以通过NavigationActions.init() 做到这一点。您可以了解更多关于导航操作here。

您可以通过创建自定义导航操作来做到这一点,阅读更多关于它们的信息here。

这里有一些代码可以为你做到这一点:

// First get a hold of your navigator
const navigator = ...

// Get the original handler
const defaultGetStateForAction = navigator.router.getStateForAction

// Then hook into the router handler
navigator.router.getStateForAction = (action, state) => 

  if (action.type === 'MyCompleteReset') 
     // For your custom action, reset it all
     return defaultGetStateForAction(NavigationActions.init())
  

  // Handle all other actions with the default handler
  return defaultGetStateForAction(action, state)

为了触发您的自定义导航操作,您必须在 React 组件中按如下方式调度它:

  this.props.navigation.dispatch(
      type: "MyCompleteReset",
      index: 0
    )

【讨论】:

***.com/questions/48059045/… 我们如何传递action.type 我需要具体的工作示例。我希望赏金+200 有所帮助 嘿@JohnBaek 查看编辑后的答案。我添加了一个如何触发您的自定义操作的示例。【参考方案2】:

这应该适用于大多数情况:

componentWillReceiveProps(nextProps) 
    if ( nextProps.token == undefined || _.isNil(nextProps.token) ) 

        let action = NavigationActions.reset(
            index: 0,
            key: null,
            actions: [
                NavigationActions.navigate(routeName: 'Auth')
            ]
        );

        nextProps.navigation.dispatch(action);
    
    ...

或者尝试通过自定义操作来增强您的导航器:

const changeAppNavigator = Navigator => 
   const router = Navigator.router;

   const defaultGetStateForAction = router.getStateForAction;

   router.getStateForAction = (action, state) => 
       if (state && action.type === "RESET_TO_AUTH") 
          let payLoad = 
              index: 0,
              key: null,
              actions: [NavigationActions.navigate(routeName: "AuthStackNavigator")]
          ;

          return defaultGetStateForAction(NavigationActions.reset(payLoad), state);
          // or this might work for you, not sure:
          // return defaultGetStateForAction(NavigationActions.init(), state)
       
       return defaultGetStateForAction(action, state);
  ;

  return Navigator;
;

const screens =  ... 

RootTabNavigator = changeAppNavigator(TabNavigator(screens, 
  initialRouteName: ...,
  ...
));

然后在你的Menuo Screen 做:

componentWillReceiveProps(nextProps) 
    if ( nextProps.token == undefined || _.isNil(nextProps.token) ) 

        nextProps.navigation.dispatch(type: "RESET_TO_AUTH");
    ...

【讨论】:

哦,代码很容易阅读,我明白它是如何工作的!但是我的 RootTabNavigator 已经定义为类。我们可以对我的 RootTabNavigator 使用相同的逻辑吗?谢谢! @JohnBaek 你应该可以在任何导航器上使用它,我在少数情况下尝试过它,为我工作,在我的项目中使用它...... 当我尝试在其他屏幕(MenuScreen > ChangePasswordScreen)上调度(type: "RESET_TO_AUTH")时,我得到 undefined is not an object(评估 '_this3._component.setNativeProps')。 . 在执行this.props.navigation.dispatch(type: "RESET_TO_AUTH"); 之前,您能否确认navigation 出现在道具上? 当然。它打印Object "dispatch": [Function anonymous], "goBack": [Function goBack], "navigate": [Function navigate], "setParams": [Function setParams], "state": Object "key": "id-xxxxx578521-6", "params": undefined, "routeName": "ChangePassword", , 【参考方案3】:

您可以通过扩展路由器来定义自定义导航逻辑。要完成您在问题的项目文件层次结构中描述的内容,您可以执行以下操作。

MainTabNavigator.js

...

RootTabNavigator.router.getStateForAction = (action, state) => 
  if (state && action.type === 'GoToAuthScreen') 
    return 
      ...state,
      index: 0,
    ;
  

  return RootTabNavigator.router.getStateForAction(action, state);
;

MainTabNavigator.router.getStateForAction = (action, state) => 
  if (state && action.type === 'GoToAuthScreen') 
    return 
      ...state,
      index: 0,
    ;
  

  return MainTabNavigator.router.getStateForAction(action, state);
;

MenuStackNavigator.router.getStateForAction = (action, state) => 
  if (state && action.type === 'GoToAuthScreen') 
    return 
      ...state,
      index: 0,
    ;
  

  return MenuStackNavigator.router.getStateForAction(action, state);
;

在菜单屏幕文件中

componentWillReceiveProps(nextProps) 
  if ( nextProps.token == undefined || _.isNil(nextProps.token) ) 
    const goToAuthScreen = () => (
      type: 'GoToAuthScreen',
    );

    nextProps.navigation.dispatch(goToAuthScreen);
    ...
  

【讨论】:

以上是关于用户注销时如何重置 TabNavigator(从其他屏幕)的主要内容,如果未能解决你的问题,请参考以下文章

点击注销时 SwiftUI 将应用程序重置为登录屏幕

当用户在 react-native 应用程序中注销时,选项卡导航器不会重置

RestKit:在注销时重置持久存储后映射了 0 个对象

注销 - Taleo 用户

如何使用php在注销时删除浏览器的本地存储项

如何将数据保存在 JSON 文件中,这样每次我的 Discord Bot 注销时数据都不会重置