loading...

React Navigation with Typescript

andreasbergqvist profile image Andreas Bergqvist ・3 min read

So.. You want to build an React Native app with Typescript and you have decided to use React Navigation as navigation library.

You have set all the Typescript stuff up and gets your app running!

You add React Navigation and all is fine!

But.. You add some screens that expects parameters and some that you want to edit the header and so on. There is not much information to find...

Here are some snippets how I have used React Navigation with Typescript.

Disclaimer

There are multiple ways of implementing typed React Navigation. These are only some examples and the naming of things should be considered to fit your application.

Any comments of other ways to solve it is appreciated!

First, classes vs functions...

I really enjoy using function components with hooks.
But currently there is an issue with hot reloading if using function components.
See: https://github.com/facebook/react-native/issues/10991

It just don't work. There might be solutions where you wrap you functional components around with classes, but hopefully this issue will soon be fixed!
https://mobile.twitter.com/dan_abramov/status/1125846420949434368

I will be using a useNavigation hook based of https://github.com/react-navigation/hooks.
But since the repo isn't very active, I just "stole" this function and modified abit:

import { useContext } from 'react';
import {
  NavigationScreenProp,
  NavigationRoute,
  NavigationContext,
} from 'react-navigation';

export function useNavigation<Params>() {
  return useContext(NavigationContext) as NavigationScreenProp<
    NavigationRoute,
    Params
  >;
}

So, my examples will be with both classes and functional components.

Update header title and navigate

Class component

import React, { Component } from 'react';
import { Button, Text, View } from 'react-native';
import {
  NavigationParams,
  NavigationScreenProp,
  NavigationState,
} from 'react-navigation';

interface Props {
  navigation: NavigationScreenProp<NavigationState, NavigationParams>;
}

class TestScreen extends Component<Props> {
  public static navigationOptions = {
    title: 'Test Screen',
  };

  render() {
    const { navigation } = this.props;
    return (
      <View>
        <Text>Test Screen</Text>
        <Button
          title="Button"
          onPress={() => {
            navigation.navigate('anotherTestScreen');
          }}
        />
      </View>
    );
  }
}

export default TestScreen;

Notice, that only screens that is set up directly on a navigation has the navigation property. If you would like a sub-component to have access to navigation you can do like this:

import React, { Component } from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationInjectedProps, withNavigation } from 'react-navigation';

class TestComponent extends Component<NavigationInjectedProps> {
  render() {
    const { navigation } = this.props;
    return (
      <Button
        title="Button"
        onPress={() => {
          navigation.navigate('anotherTestScreen');
        }}
      />
    );
  }
}

export default withNavigation(TestComponent);

Function component

import React from 'react';
import { Button, Text, View } from 'react-native';
import { useNavigation } from '../hooks/useNavigation';

const AnotherTestScreen = () => {
  const navigation = useNavigation();
  return (
    <View>
      <Text>Test Screen</Text>
      <Button
        title="Button"
        onPress={() => {
          navigation.navigate('paramScreen', { text: 'Hi!' });
        }}
      />
    </View>
  );
};

AnotherTestScreen.navigationOptions = {
  title: 'Another Test Screen',
};

export default AnotherTestScreen;

Typed params for the screens

Class component

import React, { Component } from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationScreenProp, NavigationState } from 'react-navigation';

interface NavigationParams {
  text: string;
}

type Navigation = NavigationScreenProp<NavigationState, NavigationParams>;

interface Props {
  navigation: Navigation;
}

class ParamScreen extends Component<Props> {
  public static navigationOptions = ({
    navigation,
  }: {
    navigation: Navigation;
  }) => ({
    title: navigation.state.params ? navigation.state.params.text : '',
  });

  render() {
    const { navigation } = this.props;
    const {
      state: { params },
    } = navigation;
    return (
      <View>
        <Text>Param: {params ? params.text : ''}</Text>
        <Button
          title="Button"
          onPress={() => {
            navigation.navigate('anotherParamScreen', { text: 'Hello!' });
          }}
        />
      </View>
    );
  }
}

export default ParamScreen;

Why would you bother with that much extra typings code you might ask yourself? Why not just use any?
Well, this example might not be the best, but the params are now typed and you can get intellisense help in your editor:

Function component

import React from 'react';
import { Button, Text, View } from 'react-native';
import {
  NavigationScreenProp,
  NavigationState,
  StackActions,
  NavigationActions,
} from 'react-navigation';
import { useNavigation } from '../hooks/useNavigation';

interface NavigationParams {
  text: string;
}

type Navigation = NavigationScreenProp<NavigationState, NavigationParams>;

const AnotherParamScreen = () => {
  const navigation = useNavigation<NavigationParams>();
  const {
    state: { params },
  } = navigation;
  return (
    <View>
      <Text>Param: {params ? params.text : ''}</Text>
      <Button
        title="Button"
        onPress={() => {
          const resetAction = StackActions.reset({
            index: 0,
            actions: [NavigationActions.navigate({ routeName: 'testScreen' })],
          });
          navigation.dispatch(resetAction);
        }}
      />
    </View>
  );
};

AnotherParamScreen.navigationOptions = ({
  navigation,
}: {
  navigation: Navigation;
}) => ({
  title: navigation.state.params ? navigation.state.params.text : '',
});

export default AnotherParamScreen;

Discussion

markdown guide
 

Any articles to use createStackNavigator or createAppContainer?
I'm stuck here.

stackoverflow.com/questions/574406...

 

This is amazing! I have been struggling with types and screen navigation props, this solved it, thanks

 
 
 

Can I find the source code of this tutorial?

 

Hi, currently no.. The code snippets are bits and pieces from a closed source project. Might share something later on.. But not planned.

 
 

thanks for this! I was wondering where the navigation props referenced in the docs were concretely defined. Solved my issue as well.