facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.58k stars 24.37k forks source link

Navigation Experimental Transition Animations Freeze #10574

Closed zachrnolan closed 7 years ago

zachrnolan commented 8 years ago

Description

We are experiencing a race condition where we try to set the state while the navigational experimental transition animation is still finishing, which freezes the screen. We have no way of knowing when this animation is finished, so not sure how to fix this.

It seems like Navigation Experimental is not respecting InteractionManager.runAfterInteractions (we tried it and it still let us update the state while the animation was halfway through). Does Navigation Experimental initiate a createInteractionHandle on start and clearInteractionHandle on completion?

Is there a way to know when the animation completes?

Additional Information

satya164 commented 8 years ago

cc @ericvicenti @hedgerwang

anttimo commented 8 years ago

NavigationTransitioner has onTransitionEndand onTransitionStart props you could try to use. I don't see NavigationTransitioner initiating createInteractionHandle.

What comes to the issue itself, I have had couple cases where animation transition ends until it's fully finished. I don't have any reproduction steps and it's really rare, so for me it could be that HMR or something else is causing it.

K-Leon commented 8 years ago

@anttimo i stumbled upon the same - it happenes as soon as an alert is triggered while transitioning. For example iOS asking for permissions.

anttimo commented 8 years ago

@zachrnolan @K-Leon have you turned on the native driver for your animations when this happens?

K-Leon commented 8 years ago

@anttimo IOS with Default Settings - so no native animations as far as i know (still not merged i think). For Android i used the native flag coming from this repo: https://github.com/facebook/react-native/pull/10289 without running into any issues.

Another interesting Fact is that everything works fine with an older version of navigation experimental. ( https://github.com/aksonov/react-native-experimental-navigation )

ericvicenti commented 8 years ago

I'd be happy to investigate the issue you're seeing, but I need help reproducing it.

NavigationTransitioner probably doesn't need to call createInteractionHandle because it automatically gets created by Animated: https://github.com/facebook/react-native/blob/c9960817eea008b2703657066212002557e0d939/Libraries/Animated/src/AnimatedImplementation.js#L829

The problem with Alertand permissions that @K-Leon mentioned is a known problem, and we should create a separate issue for that. Does anybody have an idea on how that should be fixed?

K-Leon commented 8 years ago

@ericvicenti i opened an issue for this https://github.com/facebook/react-native/issues/10598

zachrnolan commented 8 years ago

@anttimo How do you turn on native driver for animations?

@ericvicenti one of our views that is having the issue calls a redux action to get data from the server (promise) using Redux Loop. When you first go to this screen it never seems to freeze during the navigation transition, however, when you push route to the same screen again (with unique key) it seems to freeze almost every time.

I'm thinking that there are the following cases:

  1. Works Fine: The response happens very fast before the animation starts (animation works as expected)
  2. Works Fine: The response takes a long time (if we setTimeout for a second) (animation works as expected)
  3. Freezes: The response happens during the timeframe of the animation and it freezes.
anttimo commented 8 years ago

@zachrnolan You can see a example how it's done in the NavigationCardStack if you are not using it https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js#L221. I have turned nativeDriver off for now because of #10174.

omeid commented 8 years ago

We are experiencing the same problem, with and without the Native Animation.

@zachrnolan Does state change in your component result in any animations? Perhaps using LayoutAnimation?

I believe the freeze happens when two animations happens at once.

To make this even more interesting, doing Remote Debugging without the Native Animation, the transition never freezes, instead I get the following warnings where normally the app would freeze: Warning: Overriding previous layout animation with new one before the first began.

omeid commented 8 years ago

So #10606 maybe related.

ericvicenti commented 8 years ago

Two animations at once? Can you avoid doing that?

If it is intentional, what would that look like?

zachrnolan commented 8 years ago

@omeid The state change does not result in any animations. I've been testing more on a physical device and the freezing is happening a lot less often. Seems to happen more frequently when using the simulator. It also seems to happen when you're deeper in a navigation stack.

omeid commented 8 years ago

@ericnakagawa Say a "Notification Status" slides down as your CardStack is transitioning. Similar to #10598.

@zachrnolan Hmmm. Do you use react-redux? What transitioner? CardStack? I am trying to figure out if we are facing the same issue.

zachrnolan commented 8 years ago

@omeid I'm using react-redux and NavigationCardStack. I still haven't been able to pinpoint exactly why it's freezing.

omeid commented 8 years ago

The issue seems to be that when any Redux event occurs (which of course, includes routing) all the routes gets rerenderd.

Wrapping my "pure components" with the following mixin component before passing them to react-redux's connect seems to solve the problem. Alas, I figured this out after ditching CardStack in favour of using navigation Transitioner directly, so it may not work correctly with cardstack.

'use strict'

import React, { Component } from 'react'

export function ActiveSceneGuard (Scene) {
  return class extends Component {

    shouldComponentUpdate (nextProps) {
      return nextProps.scene.isActive
    }

    render () {
      console.debug('rendering', this.props.scene.key)
      return (
        <Scene {...this.props} />
      )
    }
  }
}

hope this solves your problem too @zachrnolan!

zachrnolan commented 8 years ago

@omeid Thanks for this! Can you show how you implemented this mixin?

omeid commented 8 years ago

@zachrnolan Sorry, I meant component instead of mixin. You just pass your component to ActiveSceneGuard before passing it to react-redux's connect.

Essentially, connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(ActiveSceneGuard(YourComponent)).

If you're not using reselect or similar, you might also consider some optimisations in your mapper functions based on whatever a scene is active or not.

davidruisinger commented 7 years ago

I got the same issue when setting/changing the navigation props during transition. I have a screen where I pass an objectId as a parameter and load the object directly when the user navigates to the screen. As soon as I fetched the object I set the title in the Header/NavBar to the object's name. If the API response comes in before the transition has finished (and I dispatch an updated state with the title) the transition freezes...

hramos commented 7 years ago

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.