You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Native自定义栈用pop()导航崩溃:Cannot read property 'state' of undefined

Hey there, let’s break down why your app crashes on pop() but works fine with navigate or goBack(). Looking at your code, error stack, and React Navigation 4.x setup, the issues boil down to navigation state handling and potential gesture conflicts. Here’s how to fix this:

What’s Causing the Crash?

  1. Missing Navigation State Prop
    When you call pop(), the underlying AuthenticatedNavigator tries to access navigation.state but can’t find it—this happens because your CustomStack isn’t properly passing the full navigation state to the nested navigator. Unlike navigate or goBack(), pop() relies directly on the current stack’s state to function.

  2. Gesture Handler Conflict
    Your UserActivity’s Pan Responder might be intercepting React Navigation’s native back gestures (like iOS swipe-to-go-back). This disrupts the navigation state update flow, leading to the state undefined error when pop() is triggered.

  3. Unpassed Navigation Object to UserActivity
    Your UserActivity class doesn’t receive the navigation object in its constructor, which could cause unexpected behavior when the inactivity logout fires—this might indirectly break the pop() flow.


Fix 1: Ensure Proper Navigation State Passing & Custom Router

Update your CustomStack to guarantee the nested AuthenticatedNavigator gets the full navigation state, and add a custom router to handle pop() correctly:

import React from 'react';
import UserActivity from 'utils/inactiveUser';
import AuthenticatedNavigator from '../AuthenticatedStack';
import { NavigationActions } from 'react-navigation';

// Wrap the AuthenticatedNavigator's router to handle edge cases for pop()
class CustomRouter extends AuthenticatedNavigator.router.constructor {
  getStateForAction(action, state) {
    // Handle pop when state is undefined to avoid crashes
    if (action.type === NavigationActions.POP && !state) {
      return super.getStateForAction(NavigationActions.init(), state);
    }
    return super.getStateForAction(action, state);
  }
}

class CustomStack extends React.Component {
  panHandlers = {};
  userActivity;

  constructor(props) {
    super(props);
    // Pass navigation to UserActivity so logout works correctly
    this.userActivity = new UserActivity(props.navigation);
  }

  componentDidMount() {
    this.userActivity.startTimer();
    this.panHandlers = this.userActivity.panHandlers();
  }

  // Use our custom router instead of directly inheriting
  static router = new CustomRouter();

  render() {
    const { navigation } = this.props;
    // Explicitly pass the full navigation state to the nested navigator
    return (
      <AuthenticatedNavigator
        screenProps={{ ...this.panHandlers }}
        navigation={{
          ...navigation,
          state: navigation.state || {}, // Fallback to empty object if state is missing
        }}
      />
    );
  }
}

export default CustomStack;

Fix 2: Adjust Pan Responder to Avoid Navigation Gesture Conflicts

Modify your UserActivity class to ignore React Navigation’s native back gestures, so they don’t interfere with pop():

// utils/inactiveUser.js
import { PanResponder } from 'react-native';

class UserActivity {
  constructor(navigation) {
    this.navigation = navigation;
    this.inactivityTimer = null;
    this.INACTIVITY_TIMEOUT = 30000; // Adjust timeout as needed
  }

  resetTimer = () => {
    clearTimeout(this.inactivityTimer);
    this.startTimer();
  };

  startTimer = () => {
    this.inactivityTimer = setTimeout(() => {
      // Safe logout navigation
      this.navigation.navigate('Auth');
    }, this.INACTIVITY_TIMEOUT);
  };

  panHandlers = () => {
    return PanResponder.create({
      // Ignore left-swipe gestures (iOS back gesture)
      onStartShouldSetPanResponder: (evt, gestureState) => {
        if (gestureState.dx < -20) { // Left swipe detected
          return false;
        }
        this.resetTimer();
        return false; // Don't intercept the touch event
      },
      // Reset timer on any touch movement
      onMoveShouldSetPanResponder: () => {
        this.resetTimer();
        return false;
      },
    }).panHandlers;
  };
}

export default UserActivity;

Fix 3: Verify Root Navigator Setup

Make sure your root navigator is using CustomStack as the authenticated stack (not nesting it incorrectly):

// Example root navigator
import { createSwitchNavigator, createAppContainer } from 'react-navigation';
import AuthStack from './AuthStack';
import CustomStack from './CustomStack';

const RootNavigator = createSwitchNavigator(
  {
    Auth: AuthStack,
    App: CustomStack, // Replace AuthenticatedStack with CustomStack here
  },
  {
    initialRouteName: 'Auth',
  }
);

export default createAppContainer(RootNavigator);

These changes should fix the pop() crash by ensuring navigation state is always available, avoiding gesture conflicts, and properly linking the UserActivity logic to the navigation system.

内容的提问来源于stack exchange,提问作者Ashish Singh Rawat

火山引擎 最新活动