iosreactjsreact-nativeexpoexpo-router

Problem with hiding & showing back drawer navigator header in nested Stack navigator


Tool :

I'm using Expo Router.

Current Logic :

I have a drawer navigator which contains several routes, from which i have a "users" route which contains a Stack Navigator. At first a users list get shown when navigating to users. Then you can click on a user to navigate to users detail. In this route i do hide the drawer navigator header and only show the stack with the back button. While navigating back to users route, i do show drawer navigator header again.

Problem : When navigating back there is a delay on the header display. It takes some milliseconds to show back again.

Demo : Video of Behavior

Code Snippets :

Drawer Layout :

export default function DrawerLayout() {
  const shoudShow = true;
  return (
    <Drawer
      drawerContent={(props) => <CustomDrawerContent {...props} />}
      screenOptions={{
        headerStyle: {
          backgroundColor: '#3084dc',
        },
        headerShown:true,
        headerTitleStyle:{fontWeight:800,fontSize:20},
        headerTitleAlign:'left',
        headerTintColor: '#fff',
        drawerActiveTintColor:'#fff',
        drawerActiveBackgroundColor:'#3084dc',
        drawerInactiveTintColor:'#3084dc',
        drawerItemStyle : {borderRadius : 8,marginBottom : 7},
        headerRight : ({tintColor})=>{return <View style={{flexDirection:'row'}}>
          <IconButton
            icon="bell-outline"
            iconColor={tintColor}
            size={24}
            rippleColor='#0000'
          />
          <IconButton
            icon="account-outline"
            iconColor={tintColor}
            size={24}
            rippleColor='#0000'
          />
          
        </View>}
      }}
    >
     <Drawer.Screen name="(tabs)"  options={{ title: 'Home', drawerIcon: ({ color,size }) => (
                 <Ionicons name="home" size={size} color={color} />
    ), }}  />
     
      <Drawer.Screen
        name="profile"
        options={{
          title: 'Profile',
          drawerIcon: ({ color,size }) => (
            <Ionicons name="person" size={size} color={color} />
          ),
        }}
      />
        <Drawer.Screen
          name="users"
          options={{
            title: 'Users',
            headerStyle:{backgroundColor:'white',borderBottomWidth:0},
            headerTintColor:'black',
            headerShown:true,
            drawerIcon: ({ color,size }) => (
              <Ionicons name="people" size={size} color={color} />
            ),
          }}
        />

      <Drawer.Screen
        name="settings"
        options={{
          title: 'Settings',
          headerStyle:{backgroundColor:'white',borderBottomWidth:0},
          headerTintColor:'black',
          drawerIcon: ({ color,size }) => (
            <Ionicons name="settings" size={size} color={color} />
          ),
        }}
      />

      <Drawer.Screen
        name="references"
        options={{
          headerStyle:{backgroundColor:'white',borderBottomWidth:0},
          headerTintColor:'black',
          headerShown:true,
          title: 'References',
          drawerIcon: ({ color,size }) => (
            <Ionicons name="person" size={size} color={color} />
          ),
        }}
      />
    </Drawer>
    
  );
}

Users Layout :

export default function UsersLayout(){

    return <Stack screenOptions={{
        headerShown : false
    }}>
        <Stack.Screen name="index"  options={{title:'Users'}}/>
        <Stack.Screen name="[userId]" options={{title:'User Details',headerShown:true}}/>
    </Stack>
}

[userId] route (In which the drawer header should be hidden):


export default function UserDetails(){
    let shownComponent = <UserInformations/>
    const [segmentValue,setSegmentValue] = useState('informations');
    const navigation = useNavigation();
    useLayoutEffect(() => {
       navigation.getParent()?.setOptions({
         headerShown: false,
       });
       return () =>
        {
         navigation.getParent()?.setOptions({
           headerShown: true,
         })};
     }, [navigation]); 
    switch(segmentValue){
        case 'informations':
            shownComponent = <UserInformations/>;
            break;
        case 'activity':
            shownComponent = <UserActivity/>
            break;
        case 'permissions':
            shownComponent = <UserPermissions/>
    }
    return (
        <ThemedView style={styles.root}>
                <UserCard left={()=><ThemedView lightColor="#ffff" style={{flex:1,alignItems:'center',justifyContent:'center'}}>
                         <Avatar.Image size={60} source ={{uri : 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRVWT916ZIZzh7ZTuRB9cq3yVWptueIy-eKYw&s'}} />
                         <ThemedText style={{fontWeight:800,color : '#969696',marginTop : 6,textAlign:'center',fontSize:12}}>Admin</ThemedText>
                    </ThemedView>}
                content={()=><ThemedView lightColor="#ffff" style={{flex:1}}>
                    <ThemedText style={{fontSize:18}}>John Doe</ThemedText>
                    <ThemedText style={{fontSize:13,color : '#969696'}}>johndoe@gmail.com</ThemedText>
                    <ThemedView style={[styles.description,{flexDirection:'row',justifyContent:'space-between',marginTop : 8}]}>
                        <ThemedView style={[styles.description,{flexDirection:'row',alignItems:'center'}]}>
                            <Ionicons name='ellipse' size={12} color='#008000'/>
                            <ThemedText style={{fontSize : 12}}> Active</ThemedText>
                        </ThemedView>
                        <ThemedText style={{fontSize : 12,paddingTop:-18}}>2hrs ago</ThemedText>
                    </ThemedView>
           </ThemedView>}
                    right={(props:any) => <List.Icon   icon="chevron-right"/>}
                />
                <Button mode='contained' style={{backgroundColor:'#3084dc',marginTop : 20,borderRadius:8}}>Reset Password</Button>
                
                <SegmentedButtons
                    value={segmentValue}
                    onValueChange={setSegmentValue}
                    style={styles.segmentContainer}
                    theme={{ roundness: 0 }}
                    buttons={[
                    { 
                        labelStyle:{fontWeight:800,fontSize:13},
                        checkedColor:'#3084dc',
                        uncheckedColor:'#3084dc',
                        value: 'informations',
                        label: 'Informations',
                        style: [styles.segmentButton,{borderBottomColor:segmentValue=='informations'?'#3084dc':'#E1E1E1'}],
                    },
                    { 
                        labelStyle:{fontWeight:800,fontSize:13},
                        checkedColor:'#3084dc',
                        uncheckedColor:'#3084dc',
                        value: 'activity',
                        label: 'Activity',
                        style: [styles.segmentButton,{borderBottomColor:segmentValue=='activity'?'#3084dc':'#E1E1E1'}]
                    },
                    { 
                        labelStyle:{fontWeight:800,fontSize:13}, 
                      checkedColor:'#3084dc',
                      uncheckedColor:'#3084dc',
                      value: 'permissions', 
                      label: 'Permissions',
                      style: [styles.segmentButton,{borderBottomColor:segmentValue=='permissions'?'#3084dc':'#E1E1E1'}] 
                    },
                    ]}
                />
                <ThemedView style={styles.segmentsContent}>
                    {shownComponent}
                </ThemedView>
        </ThemedView>
    );
}

Solution

  • Finally i've managed to solve this by hiding the stack navigator header once and for all. Then i implemented the content of the drawer header based on the current route, hence showing a back button inside the [userid] route