Skip to content

Instantly share code, notes, and snippets.

@satya164
Last active January 10, 2023 21:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save satya164/73643343a4a2b439b13704ddd92b199a to your computer and use it in GitHub Desktop.
Save satya164/73643343a4a2b439b13704ddd92b199a to your computer and use it in GitHub Desktop.
React Navigation Static API

React Navigation Static API

React Navigation has a dynamic API which makes it possible to achieve advanced and use cases. But it can result in additional boilerplate and duplication. The goal of this static API is to provide a simpler API for simple use cases.

Basic API

const MyNavigation = createNavigation({
  // Type of the navigator, takes the 'createXNavigator' function from respective package
  type: createStackNavigator,
  // Any props accepted by the navigator
  initialRouteName: 'Home',
  keyboardHandlingEnabled: false,
  // List of screens in the navigator
  screens: {
    Home: {
      // Screens with nested navigators need to specify `type` and `screens` instead of `component`
      type: createBottomTabNavigator,
      screens: {
        Feed: {
          component: FeedScreen,
          options: {
            title: 'Feed',
          },
        },
      },
    },
    Profile: {
      // The component to render for this screen
      component: ProfileScreen,
      // Options for the screen
      options: ({ route, data }) => ({
        title:
          // The additional `data` parameter can be used to configure the screen based on dynamic data
          data.me === route.params.username
            ? 'My Profile'
            : `@${route.params.username}'s Profile`,
      }),
      // ID for navigating to new screens
      getId: ({ route }) => route.params.username,
      // Path for linking integration
      path: 'profile/:username',
    },
    // It's possible to specify a component directly
    Settings: SettingsScreen,
  },
});

The MyNavigation component can be directly used or rendered to pass additional props to the NavigationContainer. It takes the same props as the NavigationContainer component except linking, which is automatically configured based on the path properties in the configuration. In addition, it also accepts a data prop that can be used to for dynamic options.

export default function App() {
  return (
    <MyNavigation
      data={{ me: 'jane' }}
      onStateChange={() => {
        // Do something on navigation
      }}
    />
  );
}

TypeScript

The TypeScript setup is different from how it's done with the regular API. Each screen component needs to specify the type of the route prop:

type Props = {
  route: {
    params: {
      username: string;
    };
  };
};

function ProfileScreen({ route }: Props) {
  // ...
}

The type of Props can be specified with the StaticScreenProps alias in a simpler way:

type Props = StaticScreenProps<{
  username: string;
}>;

The navigation prop isn't passed to the screen component with the static configuration. Users need to use the useNavigation hook instead. To TypeCheck the useNavigation hook, a default type can be specified as follows:

declare global {
  namespace ReactNavigation {
    interface RootParamList extends StaticParamList<typeof Navigation> {}
  }
}

Authentication

Since the navigation is static, it's not possible to conditionally render a screen based on the authentication state. Instead, the condition can be specified with the if property in the config:

type Data = {
  isSignedIn: boolean;
};

const MyNavigation = createNavigation<Data>({
  // ...
  screens: {
    Login: {
      if: ({ isSignedIn }) => !isSignedIn,
      component: LoginScreen,
    },
    Home: {
      if: ({ isSignedIn }) => isSignedIn,
      component: HomeScreen,
    },
  },
});

export default function App() {
  const { isSignedIn } = useAuth();

  return <MyNavigation data={{ isSignedIn }} />;
}
@intergalacticspacehighway
Copy link

Liked the idea, good API for simple use cases as you said.

Also liked the path: 'profile/:username' config. Seems intuitive. Not sure about the if API. In the above example, if isSignedIn is true, can we specify to open the HomeScreen by default (if there are multiple screens)? feels it'd be better to use the dynamic API for such cases imo.

@satya164
Copy link
Author

Not sure about the if API
feels it'd be better to use the dynamic API for such cases imo

Me neither, but the whole tree needs to be configured statically to be able to automatically setup deep linking and TS, so the mixing the dynamic API won't be an option.

if isSignedIn is true, can we specify to open the HomeScreen by default

It'd work similarly to the dynamic API, it'll take the matching screen that's defined first.

@intergalacticspacehighway
Copy link

cool. Do you plan to add support for useLinkTo with this API?

@satya164
Copy link
Author

@intergalacticspacehighway yeah, all react navigation APIs (such as useLinkTo) will work with this since this is a wrapper that internally uses the existing APIs.

@intergalacticspacehighway
Copy link

Got it. Thanks for clarifying. I can imagine myself using this API for quick prototyping and simple use cases. Also, this will work with solito as it supports useLinkTo. cc @nandorojo. I can help testing it.

@satya164
Copy link
Author

Very early prototype here react-navigation/react-navigation#11144

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment