Celestial
Celestial

Reputation: 933

React Navigation extremely slowed down

We've been using react-navigation in an app we are developing for the past 5 months.

Since yesterday the react navigator started to navigate to screens with 4-8 seconds delay. I've removed all of the variables that were being passed in screenProps and it still has the same issue.

I am testing the delay by checking the time right before the navigate() function is executed and between the componentWillMount() and i am getting 4-8 sec in between. Anyone more experienced knows why navigate() would take so long ?

Haven't made some changes in the navigator it just started acting this way :|

I am working in debug mode testing on real android device, but i've made an release to test and the delay still persists.

My navigator:

import React, { Component } from 'react';
import { createStackNavigator, HeaderBackButton, createAppContainer } from 'react-navigation';

import { colors } from 'assets/styles/colors.js';

import RegistrationInputScreen from 'components/Registration/Input.js';
import RegistrationVerificationScreen from 'components/Registration/Verification.js';
import MainScreen from 'screens/MainScreen';
import Conversation from 'components/Messages/Conversation';
import Private from 'components/FirstTime/Private.js';
import Description from 'components/FirstTime/Description.js';
import CategoriesScreen from 'components/FirstTime/CategoriesScreen.js';
import Professional from 'components/FirstTime/Professional.js';
import Home from 'components/Home.js';
import SecretScreen from 'screens/SecretScreen.js';
import Map from 'components/Map/Map.js';
import ProfileScreen from 'components/Profile/Profile.js';
import EditProfile from 'components/Profile/EditProfile.js';
import PublicProfile from 'components/Profile/PublicProfile.js';
import Settings from 'components/Profile/Settings';
import {setTopLevelNavigator, navigate} from './NavigationService';



export default class RootNavigator extends Component {
  constructor(props){
    super(props)
  }

  render() {
    console.log("PROPERTIES IN ROOT NAVIGATOR", this.props);
    return (
      <Navigator />
    );
  }
}

// ref={navigatorRef => {
//   setTopLevelNavigator(navigatorRef);
// }}
export const RootNav = createStackNavigator(
  {
    RegistrationOptions: {
      screen: Home,
      navigationOptions: {
        header: null
      },
    },
    RegistrationInput: {
      screen: RegistrationInputScreen,
      navigationOptions: ({navigation}) => (setHeader(null, navigation))
    },
    RegistrationVerification: {
      screen: RegistrationVerificationScreen,
      navigationOptions: ({navigation}) => (setHeader('Registration Verification1', navigation))
    },
    Map: {
      screen: Map,
      navigationOptions: {
        header: null
      }
    },
    MainScreen: MainScreen,
    Private: {
      screen: Private,
      navigationOptions: ({navigation}) => (setHeader('Introduce yourself', navigation))
    },
    Interests: {
      screen: CategoriesScreen,
      navigationOptions: ({navigation}) => (setHeader('Back', navigation))
    },
    Description: {
      screen: Description,
      navigationOptions: ({navigation}) => (setHeader('Describe yourself', navigation))
    },
    Professional: {
      screen: Professional,
      navigationOptions: ({navigation}) => (setHeader('Professional', navigation))
    },
    Conversation: {
      screen: Conversation,
      navigationOptions: ({navigation}) => (setHeader(null, navigation))
    },
    Secret: {
      screen: SecretScreen,
      navigationOptions: ({navigation}) => (setHeader('Configure app', navigation))
    },
    Profile: {
      screen: ProfileScreen,
      navigationOptions: ({navigation}) => (setHeader('Profile', navigation))
    },
    Public: {
      screen: PublicProfile,
      navigationOptions: ({navigation}) => (setHeader('Profile', navigation))
    },
    EditProfile: {
      screen: EditProfile,
      navigationOptions: ({navigation}) => (setHeader('Edit profile', navigation))
    },
    Settings: {
      screen: Settings,
      navigationOptions: ({navigation}) => (setHeader('Settings', navigation))
    },
  }
);

export const Navigator = createAppContainer(RootNav);

const setHeader = (title=null, navigation) => {
  let options = {
    title: title,
    headerStyle: {
        backgroundColor: colors.bgRed,
        shadowOpacity: 0,
        shadowOffset: {
            height: 0,
        },
        shadowRadius: 0,
        elevation: 0
    },
    headerTitleStyle: { color:colors.white },
    headerTransitionPreset: {headerMode: 'screen'},
    cardShadowEnabled: false,
    headerLeft: (
      <HeaderBackButton
        tintColor={colors.white} onPress={() => navigation.dispatch({ type: 'Navigation/BACK' }) }
      />
    )
  }

  if(title === null) delete options.title;

  return options;
}

Upvotes: 5

Views: 11867

Answers (5)

user10645790
user10645790

Reputation: 1274

My workaround is listening to the focus and optionally to transitionEnd events, in my components, and while it's not ready I render a placeholder. The screen transition will be smooth.

// useIsReady.ts

import { useNavigation } from '@react-navigation/native'
import React from 'react'

const useIsReady = (stack: boolean = true) => {
  const navigation = useNavigation()
  const [isReady, setIsReady] = React.useState(false)
  React.useEffect(() => {
    const unsubscribeFocus = navigation.addListener('focus', () => {
      if (!isReady) setIsReady(true)
    })

    const unsubscribeTransitionEnd = stack
      ? // @ts-ignore
        navigation.addListener('transitionEnd', () => {
          if (!isReady) setIsReady(true)
        })
      : undefined

    return () => {
      unsubscribeFocus()
      unsubscribeTransitionEnd && unsubscribeTransitionEnd()
    }
  }, [])
  return isReady
}

export default useIsReady

Some component...

const HeavyComponentThatMakeNavigationLooksCrap = () => {
  const isReady = useIsReady()
  return isReady ? ... : <Placeholder />
}

If you have multiple heavy components in the screen, it is better to use it directly in the screen:

const ScreenWithMultipleHeavyComponents = () => {
  const isReady = useIsReady()
  return isReady ? ... : <ScreenPlaceholder />
  // or
  return (
    <>
       ...
       {isReady ? ... : <ComponentsPlaceholder />}
    </>
  )
}

Just a workaround...

It's not a solution because if your component is really heavy, it is still blocking the js thread, which is also true for the react-navigation-heavy-screen solution above (see the PS below). Although the page transition will be smooth, again, the same as the above solution.

PS: I posted it originally in this issue on React Navigation

Upvotes: 3

Celestial
Celestial

Reputation: 933

The issue started appearing again and my animations were extremely slowed down too. I found out that disabling remote debugging was the cause of the navigator slow navigation and to the slowed animations. In case someone else experiences this, try disabling remote debugging.

Upvotes: 5

Charanjeet Singh
Charanjeet Singh

Reputation: 251

As there is no proper code where I can see the problem. But with react navigation animation thread is the main problem. As per my experience, you can use the InteractionManager.

Just use the below code to wait for the render.

state = { is_initiated: false };
 componentDidMount() {
    InteractionManager.runAfterInteractions(() => {
        this.setState({'is_initiated': true });
    }); 
}
render() {
  if(this.state.is_initiated) {
   return (<Component />);
  } else {
       return (<Loader />);
    }
}

Upvotes: 0

Ankush Rishi
Ankush Rishi

Reputation: 3150

This problem occurs due to loading of large amount of data in background or when you render in your app

For example: if you have a list of items and when you enter your app and the list data is very large, the whole data will not be able to render in a single time, it takes time as you scroll down the list. So In that case, either you can add pagination like load more data or filters. Try to check in which screen, there is large amount of data loaded

Upvotes: 2

Joan
Joan

Reputation: 68

When i had navigation issue, it was caused by the rendering of my screen which was really heavy. May you had some things in your screen which cause this performance ? Try to just return null; in your render of the screen and see if the issue is still there.

Which version of react-navigation do you use ?

Upvotes: 0

Related Questions