Search code examples
javascriptreact-nativereact-navigationreact-native-ui-kitten

Top navigation items in header constantly flickers when typing


The image in the header constantly flickers when I type. May I ask how do I stop this flickering at the top right hand corner or accessoryRight? I am using this TopNavigation component from UI Kitten UI library. I don't think this is normal, it shouldn't happen at all. I must be doing something wrongly.

https://youtu.be/fQppQn-RzeE (How do I embed this? Editor, thank you in advance!)

The flickering happens in the title and the right side of the Navigation Header.

I made a separate component for the TopNavigation and then call it in respective screens.

Things I have tried:

  • Since the outcome of the Header relies on navigation props, I tried using useState and useEffect (with navProps as the dependency) to save the prop instead of reading directly from props, but to no avail
  • Directly adding the jsx into the TopNavigation's accessoryLeft/Right and title options

Any input is welcome, appreciate it!

TopNavigation:

const NavHeader = ({ navProps }) => {
  const navigateBack = () => {
    navProps.navigation.goBack();
  };

  const [type, setType] = React.useState('');

  React.useEffect(() => {
    setType(navProps.type);
  }, [navProps]);

  const BackIcon = props => <Icon {...props} name='arrow-back' />;

  const BackAction = () => (
    <TopNavigationAction icon={BackIcon} onPress={navigateBack} />
  );

  const renderBrand = () => (
    <View style={styles.titleContainer}>
      <Image source={require('../../assets/images/brand.png')} />
    </View>
  );

  const renderLogo = () => (
    <Image source={require('../../assets/images/logo.png')} />
  );

  return (
    <TopNavigation
      style={styles.topNav}
      accessoryLeft={navProps.backNav && BackAction}
      accessoryRight={
        type === 'register' || type === 'profile' ? renderLogo : null
      }
      title={type === 'landing' || type === 'auth' ? renderBrand : null}
      alignment='center'
    />
  );
};

Import example:

<KeyboardAvoidingView
      style={styles.kbContainer}
      behavior={Platform.OS === 'ios' ? 'padding' : null}
    >
  <SafeAreaView style={styles.parentContainer}>
    <NavHeader navProps={navProps} /> // Imported custom Header component here
    <ScrollView>
      {other content}
    </ScrollView>
  </SafeAreaView>
</KeyboardAvoidingView>

Solution

  • Perhaps requiring the images just one time and not on every render may help. Try adding this at the top of the file (not inside a component function)

    const brandImage = require('../../assets/images/brand.png');
    const logoImage = require('../../assets/images/logo.png');
    

    And then in your props instead of an inline require use the variables:

    const renderBrand = () => (
        <View style={styles.titleContainer}>
          <Image source={brandImage} />
        </View>
      );
    
      const renderLogo = () => (
        <Image source={logoImage} />
      );
    
    

    Edit:

    Since this didn't work, perhaps utilizing useMemo to memoize the components that show the images would work?

    Something like

    
    const renderBrand = useMemo(() => (
        <View style={styles.titleContainer}>
          <Image source={brandImage} />
        </View>
      ),[]);
    
      const renderLogo = useMemo(() => (
        <Image source={logoImage} />
      ),[]);