rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

Discuss cases where shallow navigation options are difficult to use

Open brentvatne opened this issue 7 years ago • 11 comments

Please take into account the justification in https://github.com/react-navigation/rfcs/blob/master/text/0005-shallow-navigation-options.md when discussing this

  • https://github.com/react-navigation/react-navigation/issues/4120

brentvatne avatar May 08 '18 00:05 brentvatne

The solution provided only works for navigators that are direct descendants of the TabNavigator. For nested navigators navigation.state does not change.

// Main Tab navigator
export default createBottomTabNavigator(
  {
    Posts: {
      screen: Posts, // Posts.jsx
      navigationOptions: ({ navigation }: any) => {
        let tabBarVisible = true

        if (navigation.state.index > 0) {
          tabBarVisible = false
        }

        return {
          tabBarVisible,
      },
    },
    Lecturers: {
      screen: Lecturers, // Lecturers.jsx
      navigationOptions: ({ navigation }: any) => {
        let tabBarVisible = true

        if (navigation.state.index > 0) {
          tabBarVisible = false
        }

        return {
          tabBarVisible,
        },
    }
}
// Posts.jsx
export default createStackNavigator(
  {
    posts: {
      screen: Posts,
    },
    viewPost: {
      screen: ViewPost,
    },
    searchPosts: {
      screen: SearchPosts,
    },
  },
  {
    headerMode: 'screen',
  }
)

Posts.jsx works as expected since it's one level deep.


// Lecturers.jsx
const PushStack = createStackNavigator(
  {
    lecturers: {
      screen: Lecturers,
    },
    viewLecturer: {
      screen: ViewLecturer,
    },
    viewCourse: {
      screen: ViewCourse,
    },
  },
  {
    headerMode: 'screen',
  }
)

export default createStackNavigator(
  {
    Main: {
      screen: PushStack,
    },
    newReview: {
      screen: NewReview,
    },
    search: {
      screen: Search,
    },
  },
  {
    mode: 'modal',
  }
)

However Lecturers.jsx doesn't work because it has a nested stack.

Example video: https://www.useloom.com/share/8278cf55d92a452d9818df5e132d0ac7

iRoachie avatar Jun 04 '18 11:06 iRoachie

An ideal way I can think of accomplishing this is to introduce a tabBarHiddenOn property that would contain all the screens by key, that the tabBar should be hidden on. By default tabBarVisible would be set to true. This would be a far cleaner solution than writing logic based on the index.

In the above example it could look like this:

export default createBottomTabNavigator(
{
    Posts: {
      screen: Posts,
      navigationOptions: {
        tabBarHiddenOn: [ 'viewPost', 'searchPosts' ]
      }
    }
}

iRoachie avatar Jun 04 '18 12:06 iRoachie

@brentvatne can you look into this issue. My app update is pending due to this issue. Your current update to this navigationOptions seems not at all intuitive ones navigators start getting nested.

ravirajn22 avatar Jun 04 '18 12:06 ravirajn22

I read the documentation for "A stack contains a tab navigator and you want to set the title on the stack header". The suggested solution works for setting header titles. But it quickly breaks down when we need control things more complicated than the title.

Our problem with the approach is that the navigator needs to know about how the header should behave with each screen. We have some button controls in the header that interacts with the content of the screen. It makes more sense to have the button logic in the navigationOptions of each screen than in the navigator.

See https://github.com/react-navigation/react-navigation.github.io/issues/152#issuecomment-391583282 where I explained the use case before.

leethree avatar Jul 04 '18 06:07 leethree

@leethree yes even I faced the same issue, it just doesn't feel right to put the navigationOptions for a particular screen in the navigator and also it does not work when having buttons which setParams. But in those cases, they are recommending to go with the first option of putting each Tab screen as a separate Stack and control the header for these Stacks individually. But I don't know if this is the right way to go.

ravirajn22 avatar Jul 04 '18 11:07 ravirajn22

can people create some snacks with examples of their problems please? https://snack.expo.io

brentvatne avatar Jul 04 '18 19:07 brentvatne

@brentvatne Here's the snack for my scenario above https://snack.expo.io/@roach_iam/react-navigation-tabs-nested-stacks. As you can see the tabBar doesn't hide for the Lecturers stack.

iRoachie avatar Jul 05 '18 01:07 iRoachie

@leethree and @iRoachie how did you solve this problem? I am still waiting for a fix to this problem. @brentvatne I think u should look into this issue. What used to be a normal solution in v1.0, seems now like a huge code mess and still, I can't make it work in v2.0.

ravirajn22 avatar Oct 02 '18 07:10 ravirajn22

@ravirajn22 I didn’t actually solve it per say. I used a workaround in that I moved all my modals into one navigator at the root of my app.

iRoachie avatar Oct 02 '18 13:10 iRoachie

@ravirajn22 No we haven't found a clean solution for this, so we are still using v1.0 🤷‍♂️

leethree avatar Oct 02 '18 23:10 leethree

The only thing that worked for me

const homeScreenStack = createStackNavigator({
  Home: {
    screen: Home,
    navigationOptions: ({ navigation }) => ({
      title: "Home"
    })
  },
  Comments: {
    screen: Comments,
    navigationOptions: ({ navigation }) => ({
      title: "Comments"
    })
  }
});

homeScreenStack.navigationOptions = ({ navigation }) => {
  let tabBarVisible = true;
  for (let i = 0; i < navigation.state.routes.length; i++) {
    if (navigation.state.routes[i].routeName == "Comments") {
      tabBarVisible = false;
    }
  }

  return {
    tabBarVisible
  };
};

2diegoduque avatar Aug 01 '19 03:08 2diegoduque