Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an embedded Stack navigator inside a React Native formSheet modal?

Like so:

enter image description here

I'm running react-navigation v4.

like image 263
Lucas C. Feijo Avatar asked Jun 08 '20 08:06

Lucas C. Feijo


People also ask

How do you use the stack navigator inside a tab navigator?

Stack navigators nested inside each screen of drawer navigator - The drawer appears over the header from the stack. Stack navigators nested inside each screen of tab navigator - The tab bar is always visible. Usually pressing the tab again also pops the stack to top.


1 Answers

First you have to follow the tutorial on how to set up a react-navigation modal, the one that has a jump animation and doesn't look like the native formSheet. You have to set up a stack navigator with your root navigator as one child and the modal as another:

enter image description here

And it scales, because you can have more than one of these modals as children.

The code for this is the following:

const RootNavigator = createStackNavigator(
  {
    index: { screen: AppNavigator },
    [NC.SCREEN_ROOM_INFO]: { screen: RoomInfoNavigator },
    [NC.SCREEN_CHAT_CREATE]: { screen: RoomCreateNavigator },
    [NC.SCREEN_CHAT_SEARCH]: { screen: ChatSearchNavigator },
    [NC.SCREEN_CHAT_GIF_PICKER]: { screen: GifPickerNavigator }
  },
  {
    mode: 'modal',
    headerMode: 'none',
    transitionConfig: () => ({
      transitionSpec: {
        duration: 0
      }
    }),
    transparentCard: true
  }
)

Then you need to implement these, from my example, 4 navigators that will be displayed as modals each like so:

// Here you'll specify the screens you'll navigate in this modal, starting from index.
const RoomInfoStack = createStackNavigator({
  index: { screen: NavigableRoomInfo },
  [NC.SCREEN_ROOM_ROSTER]: { screen: NavigableRoomRoster },
  [NC.SCREEN_ROOM_NOTIFICATION_PREFERENCES]: { screen: NavigableRoomNotificationPreferences },
  [NC.SCREEN_ROOM_EDIT]: { screen: NavigableRoomEdit }
})

type NavigationComponent<T = any> = {
  navigation?: NavigationScreenProp<NavigationState, T>
}

type Props = NavigationComponent

// THIS code is from the react-navigation tutorial on how to make a react-navigation modal:
// https://reactnavigation.org/docs/4.x/custom-navigators/#extending-navigators

class RoomInfoNavigator extends React.Component<Props> {
  static router = {
    ...RoomInfoStack.router,
    getStateForAction: (action, lastState) => {
      // check for custom actions and return a different navigation state.
      return RoomInfoStack.router.getStateForAction(action, lastState)
    }
  }

  constructor(props) {
    super(props)
    this.onClose = this.onClose.bind(this)
  }

  onClose() {
    this.props.navigation?.goBack()
  }

// And here is the trick, you'll render an always open RN formSheet
// and link its dismiss callbacks to the goBack action in react-navigation
// and render your stack as its children, redirecting the navigator var to it in props.

  render() {
    return (
      <Modal
        visible={true}
        animationType={'slide'}
        supportedOrientations={['portrait', 'landscape']}
        presentationStyle={'formSheet'}
        onRequestClose={() => this.onClose()}
        onDismiss={() => this.onClose()}
      >
        <RoomInfoStack {...this.props} />
      </Modal>
    )
  }
}

export { RoomInfoNavigator }

This export is what our root stack imported before. Then you just need to render the screens, I have a pattern that I do to extract the navigation params to props in case this screen is ever displayed without navigation:

const NavigableRoomInfo = (props: NavigationComponent<RoomInfoProps>) => {
  const roomInfo = props.navigation!.state!.params!.roomInfo
  const roomInfoFromStore = useRoomFromStore(roomInfo.id)
  
  // Here I update the navigation params so the navigation bar also updates.
  
  useEffect(() => {
    props.navigation?.setParams({
      roomInfo: roomInfoFromStore
    })
  }, [roomInfoFromStore])

  // You can even specify a different Status bar color in case it's seen through modal view:

  return (
    <>
      <StatusBar barStyle="default" />
      <RoomInfo roomInfo={roomInfoFromStore} navigation={props.navigation} />
    </>
  )
}

Sources: https://reactnavigation.org/docs/4.x/modal

https://reactnavigation.org/docs/4.x/custom-navigators/#extending-navigators

like image 135
Lucas C. Feijo Avatar answered Oct 20 '22 18:10

Lucas C. Feijo