Search code examples
typescriptreact-nativenavigationreact-navigationreact-typescript

switching between screens in react-native app


I am creating this app in react-native and I was trying to create the navigation for it and I stumbled upon the react-native documentation but I don't quite understand how to implement it. So this is the guide is was following navigation guide but it refers at some point where you give an object called "navigation" with your component. Like this

const HomeScreen = ({navigation}) => {
  return (
    <Button
      title="Go to Jane's profile"
      onPress={() =>
        navigation.navigate('Profile', {name: 'Jane'})
      }
    />
  );
};

But as far as I understand the guide it nevers tell you what this object is, I assumed it was the stack you had to create something like this.

const Stack = createNativeStackNavigator();

const Navigation = () => {
  return (
    <NavigationContainer>
      
      <Stack.Navigator initialRouteName='Login'>
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Schedule" component={ScheduleBody} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default Navigation;

This is my navigation example and I also give this "navigation" object with my pages that it needs.

const Header = ({navigation}) => {
  const [hasWorkout, setHasWorkout] = React.useState(false);

  useEffect(() => {
    setHasWorkout(false);
  }, []);

  const toggleActiveWorkout = () => {
    setHasWorkout(!hasWorkout);
  };

  const handleCalender = () => {
    
    navigation.navigate('Schedule');
  };

  return (
      <View>
        <View style={styles.centerContainer} >
            {hasWorkout ? (
                <Image style={styles.textLeft} source={ activeWorkout } />
            ) : (
                <Image style={styles.textLeft} source={ restDay } />
                )}
            <Text style={styles.textCenter}>25<Image style={styles.streak} source={streak_25}/></Text>
            <TouchableOpacity style={styles.textRight} activeOpacity={0.5} onPress={handleCalendar}>
                <Image
                source={calendar}
                />
            </TouchableOpacity>
        </View>
      </View>
    );
  };

In my app.tsx I did this

const Stack = createNativeStackNavigator();

const App = () => {
  const [loggedIn, setLoggedIn] = React.useState(false);

  const checkLoggedIn = async () => {
    const user = await AsyncStorage.getItem('user');
    if (user) {
      setLoggedIn(true);
    }
  };

  useEffect(() => {
    
    checkLoggedIn();
  }, []);
  return (
      <NavigationContainer>
        <View style={styles.container}>
          <Header navigation={Stack}/>
          <ScrollView>
            {loggedIn ? <Body /> : <Login />}
          </ScrollView>
          <Footer navigation={Stack} />
        </View>
      </NavigationContainer>
  );
};

But on my header.tsx where I want the navigation I always get the error Binding element 'navigation' implicitly has an 'any' type. I think the problem is with the app.tsx. Any help is greatly appreciated.


Solution

  • It's not a problem with app.tsx. When you want to use navigation inside Typescript, you need to type out the routes and its params. So for your case it would be something like this:

    type AuthStackParams = {
        Home: undefined;
        Schedule: undefined;
    }
    

    and then in your definition of Stack you do something like this:

    const SomeNavigation = CreateStackNavigator<AuthStackParams>();
    

    Second, InitialRouteName must be a value from your defined stack variable, so Login here is invalid

    And in the view itself, when u use useNavigation() hook, you also need to type it like this:

    const navigation = useNavigation<StackNavigatorProp<AuthStackParamList>>()
    

    and when you use this hook you will be able to get hints about the navigation destination. If you want to use the navigation to navigate to other navigation stack, you can create a global navigation function, or type out root navigator props, but I see that you get it from the prop, but you still need to type it out so that typescript won't be mad about implicit any type