Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InteractionManager.runAfterInteractions not running at all! #94

Open
mrousavy opened this issue Jul 29, 2020 · 7 comments
Open

InteractionManager.runAfterInteractions not running at all! #94

mrousavy opened this issue Jul 29, 2020 · 7 comments

Comments

@mrousavy
Copy link

mrousavy commented Jul 29, 2020

First off

First off, I had a really hard time debugging this, and I've already opened issues at react-native, react-navigation and react-native-screens. I've eliminated all possible causes for this, and finally came to the conclusion that the library causing this issue is react-navigation-shared-element.

Description

I am using a lot of InteractionManager.runAfterInteractions(() => ...) calls throughout my project.

For example, I have a feed of multiple posts in my HomeScreen (Tab Navigator) and each post has useEffect and useFocusEffect hooks which call InteractionManager.runAfterInteractions inside the hook to schedule loading extra post data after some animations have completed. "Some animations" = mostly navigation transitions from react-navigation-shared-element, but since the post items specifically are inside a Tab Navigator, no navigation transitions/animations are run so this should fire almost immediately.

In development/debug build everything works fine, but once I build for production/release, the extra post data never gets loaded, a test Alert.alert(...) I've put in there never gets shown, and my animations will never start, causing my app to be fully stuck.

I have added a GlobalErrorHandler callback to my entry point (App.tsx) since I thought "hey, maybe some JS error is thrown and execution is stopped?":

const defaultErrorHandler = ErrorUtils.getGlobalHandler();
ErrorUtils.setGlobalHandler((error, isFatal) => {
	Alert.alert(`Unexpected ${isFatal ? 'fatal error' : 'error'}!`, `Unexpected error occured! ${JSON.stringify(error)}`);
	Logger.logError(isFatal ? 'A fatal, unhandled error occured!' : 'An unhandled error occured!', error);
	if (defaultErrorHandler) defaultErrorHandler(error, isFatal);
});

but this doesn't get called either.

Unfortunately, since this only happens on production/release builds, I'm having a hard time debugging this. I will happily provide any extra information needed.


Extra Details

My root view is a NavigationContainer, and inside of it, I conditionally render the LoginStackNavigator or the HomeStackNavigator depending if the user is logged in or not. I'll go over my navigation hierachy in a bit


Current Behavior

Right now, the InteractionManager does not call the callback function at all, causing my app to be "broken". Data is never getting loaded, delayed animations are not getting started, etc.

Expected Behavior

The InteractionManager should call the callback after animations have finished. (Which, on a Tab navigator, should be instantly.)


Screenshots

Debug/Development Build Release/Production Build
Everything working fine, all InteractionManager.runAfterInteraction callbacks inside my useEffect hooks are being called. Everything is broken, InteractionManager.runAfterInteraction callbacks inside my useEffect hooks are not being called, the text for the post is not being loaded (which is inside an InteractionManager.runAfterInteraction callback), and weirdly the react-native-vector-icons are not being displayed. no idea why that's the case, since that has nothing to do with an InteractionManager.runAfterInteraction callback.

When the InteractionManager.runAfterInteractions doesn't get called, my views are also not yet enabled so the user can't actually use the app at all.

How to reproduce

  1. Create awesome app
  2. Use react-navigation for navigation, create NavigationContainer, in my case a Stack Navigator containing a Tab Navigator (Home) and a "Post Details Screen".
  3. Add InteractionManager.runAfterInteractions(() => ...) callbacks in your components (e.g. useEffect() hook)
  4. Callbacks will be called in debug, but never in release

Navigation Structure

Dumbed down, I have the following Navigation Structure:

  • NavigationContainer
    • Stack.Navigator from createNativeStackNavigator
      • Some Screens like an Add Screen which are irrelevant here
      • A Stack.Navigator from createSharedElementStackNavigator
        • Bottom Tabs with 4 Screens from createBottomTabNavigator
          • Home Screen which contains a list of Posts with the <SharedElement> inside
          • other tabs
        • Post Details Screen which is just a simple Screen with the <SharedElement> inside

My Tab Navigator's Screens (Home Screen, ...) are nested within another Shared Element Stack because of #80

My Environment

software version
iOS or Android iOS, 13.5.1
react-native-shared-element ^0.7.0
react-navigation-shared-element ^3.0.0
@react-navigation/native 5.7.1
react-native-screens ^2.9.0
react-native 0.63.2
react-native-gesture-handler ^1.7.0
@react-native-community/masked-view ^0.1.10
react-native-reanimated ^1.10.1
react-native-safe-area-context ^3.0.7
node v14.4.0
npm or yarn npm, 6.14.6

Conclusion

I would really appreciate some help with this. I am having an incredibly hard time finding the cause for this and cannot release my app for production.

I have tried rewriting my app to use wix/react-native-navigation, and noticed that all InteractionManagers work correctly there.

@mrousavy
Copy link
Author

Forgot to mention; When I replaced my SharedElement Stack Navigator with a createNativeStackNavigator from rn-screens everything worked perfectly fine (well, without the Shared Element transition obviously).

I've uploaded my source code for the SharedElement Stack Navigator here.

@mrousavy
Copy link
Author

mrousavy commented Jul 29, 2020

@IjzerenHein Maybe some animations (timing, spring, ..) are implicitly isInteraction: true when they in fact should be isInteraction: false? (see: https://reactnative.dev/docs/animated#timing)

@Svarto
Copy link

Svarto commented Jan 25, 2021

@mrousavy I have the same issue sometimes with InteractionManager, just started trying to narrow it down. Did you find a solution to this?

@mrousavy
Copy link
Author

@Svarto after a while of debugging I switched to react-native-navigation which solved the problem for me.

@aqalalwa
Copy link

@mrousavy I've had the same issue with react-navigation but was able to fix it by modifying all animations in my code to use isInteraction: false OR by switching to native driver useNativeDriver: true

@IjzerenHein
Copy link
Owner

Hey if anyone can add a repro case to the example app, then i can have a look at this. For now, I really don't understand what's going on and how the shared-element stack-navigator could affect InteractionManager in any way..

@cawfree
Copy link

cawfree commented Mar 2, 2022

Bumped into something similar.

During onPanResponderGrant, a PanResponder makes a call to createInteractionHandle which effectively blocks all calls to runAfterInteractions until the handle has been cleared. The value of the handle is stored in the PanResponder's local state, and when PanResponder terminates, if the handle is found to be !== null, it is cleared and the pending tasks are flushed.

In our application, we had a PanResponder stored in useMemo which was being reallocated due to a dependency change during an ongoing gesture. This meant that the originally latched createInteractionHandle value becomes orphaned, and all attempts to runAfterInteractions are subsequently blocked since upon termination of the newly created PanResponder it has no reference to the originally latched interaction handle.

In the calling component, you can latch the handle as follows:

const handle = React.useRef<number | null>(null);

// onPanResponderGrant
handle.current = panResponder.getInteractionHandle() as number | null;

// onPanResponderTerminate
handle.current !== null && InteractionManager.clearInteractionHandle(handle.current);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants