react-native: regression on InteractionManager.runAfterInteractions(f), not always calling f
Since RN 0.28, InteractionManager.runAfterInteractions(f)
happen to sometimes never call f
.
I couldn’t reproduce it with some simple code, but I have an app that schedule stuff in background when leaving a screen, and use InteractionManager.runAfterInteractions
when re-entering the screen (which happen during the navigator transition) and sometimes f
is not called.
Should we assume that runAfterInteractions
can sometimes not happen, since it’s a cancellable now? (but i’m not using cancel() anywhere in my code)
or is this a bug?
Thanks
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 29
- Comments: 47 (28 by maintainers)
Commits related to this issue
- Make InteractionManager tasks cancellable Summary: Returns a promise-like object with a new cancel function that will dig through the queue and remove relevant tasks before they are executed. Handy w... — committed to facebook/react-native by sahrens 8 years ago
- Don't use InteractionManager - facebook/react-native#8624 — committed to satya164/PocketGear by satya164 8 years ago
- Fixed issue with PanResponder not clearing interaction handler correctly. https://github.com/react-navigation/react-navigation/issues/4144 https://github.com/facebook/react-native/issues/8624 — committed to fram-x/FluidTransitions by chrfalch 6 years ago
quick workaround if anyone interested.
@Exilz @jqn @aforty I had this exact issue. Solved it: The callback for
InteractionManager.runAfterInteractions
was never being called. Turns out that when components are unmounted, their animations are not stopped completely. I had aAnimated.decay
animation which seems to make InteractionManager never return. Callingthis.myDecayAnimation.stopAnimation()
incomponentWillUnmount()
did not work for me (more on this below).For me, a couple of things worked:
isInteraction: false
. E.g.Animated.decay(this.myDecayAnimation, {velocity: 1/5, isInteraction: false});
This is an undocumented feature that tells RN that your animation will not block InteractionManager. This solved it for me, but I kept looking.Animated.Value().start(...)
where I was conditionally repeating the animation.Regarding 2: The callback was checking
this.state.shouldAnimate === true
. If true, it re-ran the animation. The problem was that the callback was being run after the component unmounted, but without access to the correct state, resulting in the animation being run a second time, thus making mystopAnimation
useless.You may have similar looping animations or
stopAnimation
code that isn’t really stopping your animation, or you could be assuming that your animation stops when the component is unmounted, regardless of your loops. Re-check all those assumptions and see where it gets you.In my case it was a looping animation (i.e. with the
Animated
API) that preventedf
from being called. For now I’m going to replace the animation with a static element. I wonder if it’s possible to makerunAfterInteractions
work with an infinitely looping animation elsewhere.this is still happening on RN51
Has anyone figured out a fix for this issue. I randomly started experiencing this with RN 0.40 Android. It used to work great before.
This is a major issue for me as well and not consistently reproducible either. I hope someone tracks this down. Every time I think I think it’s fixed it rears its ugly head again and causes my components not to load after navigation.
Ok, so seems
InteractionManager
not calling the callback also happens for me. I added a breakpoint and found that_interactionSet.size
is always>= 1
, so something in not clearing the interaction handle. I don’t usecreateInteractionHandle
in my code, and I don’t think any packages I use, use it either.Edit: Seems if the panHandler gets removed before releasing the touch, it never clears the handle
@gre: no, I’m not sure where you got that. All tasks scheduled with
runAfterInterActions
should be executed in order after interactions complete. If the interactions never complete (e.g. infinite animation) then those tasks (and any subsequently scheduled tasks) will ever get run. If you ever schedule tasks A then B withrunInteractionManager
and you don’t see A run before B but B does run, there is definitely a bug (assuming you didn’t cancel A).Separately, animations should be stopped when the component being animated unmounts, which should allow
runAfterInteractions
to continue if those animations were blocking it. If that’s not happening, that’s also a bug, although the previous reports indicate that the problems were in user code erroneously creating an infinite loop.I think the crux here is if the task is forever delayed (e.g. by animations running forever), of if the task is getting dropped entirely.
When you see the call not happen when you expect, do any further runAfterInteractions tasks get executed? If the problem is an infinite animation, I would expect the whole runAfterInteractions queue to get wedged. If hats not happening, there is definitely a bug.
And as @satya164 said, if you don’t want the task to wait on interactions or animations, don’t use runAfterInteractions 😛. If you want to do things while running an animation, you will likely drop animation frames - that’s the whole point - but the better fix is to switch to useNativeDriver which shouldn’t have that problem since it runs natively and will not be interrupted by any slow JS execution.
Getting bit badly by this.