最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - React Native Navigation Issue: Conditional Navigator Rendering Leads to Blank Screen - Stack Overflow

programmeradmin0浏览0评论

Hello React Native experts,

I am facing an issue with conditional navigation in my React Native app where switching between navigators based on a state leads to a blank screen. Here are the details:

Problem Description:

My app is structured to conditionally render one of two navigators (OnboardingNavigator or TabNavigator) based on an isOnboarded state. Despite the OnboardingStart screen loading perfectly when directly navigated from App.js (when hardcoded), integrating a condition to switch between the navigators results in a blank screen.

Behavior Observed:

If App.js directly sets OnboardingNavigator, OnboardingStart works without issues. When using the conditional logic based on isOnboarded, it results in a blank screen even though console logs confirm that isOnboarded is being retrieved correctly and is set to false.

Questions:

Could there be an issue related to state updates or conditional rendering in React Native that might be causing this? What debugging strategies or practices can I use to further diagnose and resolve this issue?

Any insights or advice on how to handle this kind of navigation setup would be greatly appreciated!

import React, { useState, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import OnboardingNavigator from './navigation/OnboardingNavigator';
import TabNavigator from './navigation/TabNavigator';

const App = () => {
  const [isOnboarded, setIsOnboarded] = useState(null);

  useEffect(() => {
    const checkOnboarding = async () => {
      try {
        const onboarded = await AsyncStorage.getItem('@onboarded');
        console.log('Onboarded Status:', onboarded);
        setIsOnboarded(onboarded === 'true');
      } catch (error) {
        console.error('Failed to fetch onboarding status:', error);
      }
    };

    checkOnboarding();
  }, []);

  return (
    <NavigationContainer>
      {isOnboarded ? <TabNavigator /> : <OnboardingNavigator setIsOnboarded={setIsOnboarded} />}
    </NavigationContainer>
  );
};

export default App;

This is OnboardingNavigator:

import { createStackNavigator } from '@react-navigation/stack';
import { Button, Alert } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

import OnboardingStart from '../screens/onboarding/OnboardingStart';
import OnboardingLogin from '../screens/onboarding/OnboardingLogin';
import OnboardingLoginEmail from '../screens/onboarding/OnboardingLoginEmail';
import OnboardingBorn from '../screens/onboarding/OnboardingBorn';
import OnboardingHourly from '../screens/onboarding/OnboardingHourly';
import OnboardingGoal from '../screens/onboarding/OnboardingGoal';
import OnboardingSaving from '../screens/onboarding/OnboardingSaving';
import OnboardingSavingThings from '../screens/onboarding/OnboardingSavingThings';
import OnboardingSavingHardwork from '../screens/onboarding/OnboardingSavingHardwork';
import OnboardingSavingStopping from '../screens/onboarding/OnboardingSavingStopping';
import OnboardingSavingRetirement from '../screens/onboarding/OnboardingSavingRetirement';
import OnboardingTime from '../screens/onboarding/OnboardingTime';
import OnboardingTimeBuyBack from '../screens/onboarding/OnboardingTimeBuyBack';
import OnboardingTimeWork from '../screens/onboarding/OnboardingTimeWork';
import OnboardingTracker from '../screens/onboarding/OnboardingTracker';
import OnboardingPaywall from '../screens/onboarding/OnboardingPaywall';

const OnboardingStack = createStackNavigator();

function OnboardingNavigator({ setIsOnboarded }) {
  const handleCompleteOnboarding = async () => {
    try {
      await AsyncStorage.setItem('@onboarded', 'true');
      setIsOnboarded(true);
    } catch (error) {
      console.error("Failed to set onboarding complete:", error);
      Alert.alert("Error", "Failed to complete onboarding. Please try again.");
    }
  };

  return (
    <OnboardingStack.Navigator screenOptions={{ headerShown: false }}>
      <OnboardingStack.Screen name="OnboardingStart" component={OnboardingStart} />
      <OnboardingStack.Screen name="OnboardingLogin" component={OnboardingLogin} />
      <OnboardingStack.Screen name="OnboardingLoginEmail" component={OnboardingLoginEmail} />
      <OnboardingStack.Screen name="OnboardingBorn" component={OnboardingBorn} />
      <OnboardingStack.Screen name="OnboardingHourly" component={OnboardingHourly} />
      <OnboardingStack.Screen name="OnboardingGoal" component={OnboardingGoal} />
      <OnboardingStack.Screen name="OnboardingSaving" component={OnboardingSaving} />
      <OnboardingStack.Screen name="OnboardingSavingThings" component={OnboardingSavingThings} />
      <OnboardingStack.Screen name="OnboardingSavingHardwork" component={OnboardingSavingHardwork} />
      <OnboardingStack.Screen name="OnboardingSavingStopping" component={OnboardingSavingStopping} />
      <OnboardingStack.Screen name="OnboardingSavingRetirement" component={OnboardingSavingRetirement} />
      <OnboardingStack.Screen name="OnboardingTime" component={OnboardingTime} />
      <OnboardingStack.Screen name="OnboardingTimeBuyBack" component={OnboardingTimeBuyBack} />
      <OnboardingStack.Screen name="OnboardingTimeWork" component={OnboardingTimeWork} />
      <OnboardingStack.Screen name="OnboardingTracker" component={OnboardingTracker} />
      <OnboardingStack.Screen
        name="OnboardingPaywall"
        component={OnboardingPaywall}
        options={{
          headerRight: () => (
            <Button onPress={handleCompleteOnboarding} title="Done" />
          )
        }}
        initialParams={{ setIsOnboarded: setIsOnboarded }} // Pass the setIsOnboarded down as a param
      />
    </OnboardingStack.Navigator>
  );
}

export default OnboardingNavigator;

and this is TabNavigator:

import { View, StyleSheet, TouchableOpacity } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons'; // Ensure this is installed
import Main from '../screens/Main';
import Lifetime from '../screens/Lifetime';
import Settings from '../screens/Settings';
import { createStackNavigator } from '@react-navigation/stack';

const Tab = createBottomTabNavigator();

// Custom Tab Bar Component
const CustomTabBar = ({ state, descriptors, navigation }) => {
  return (
    <View style={styles.tabBarContainer}>
      {state.routes.map((route, index) => {
        const { options } = descriptors[route.key];
        const isFocused = state.index === index;

        const onPress = () => {
          const event = navigation.emit({
            type: 'tabPress',
            target: route.key,
          });

          if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name);
          }
        };

        const getIconName = (routeName) => {
          switch (routeName) {
            case 'Lifetime':
              return 'home-outline';
            case 'Main':
              return 'cash-outline';
            case 'Settings':
              return 'person-outline';
            default:
              return 'ellipse-outline';
          }
        };

        return (
          <TouchableOpacity
            key={route.name}
            accessibilityRole="button"
            accessibilityState={isFocused ? { selected: true } : {}}
            accessibilityLabel={options.tabBarAccessibilityLabel}
            testID={options.tabBarTestID}
            onPress={onPress}
            style={styles.tabButton}
          >
            <Ionicons
              name={getIconName(route.name)}
              size={31}
              color={isFocused ? 'black' : 'gray'} // Black for active, gray for inactive
            />
          </TouchableOpacity>
        );
      })}
    </View>
  );
};

// **Main Tab Navigator Component**
const TabNavigator = () => (
  <Tab.Navigator
    initialRouteName="Main"
    screenOptions={{
      headerShown: false,
    }}
    tabBar={(props) => <CustomTabBar {...props} />}
  >
    <Tab.Screen name="Lifetime" component={Lifetime} />
    <Tab.Screen name="Main" component={Main} />
    <Tab.Screen name="Settings" component={Settings} />
  </Tab.Navigator>
);

export default TabNavigator;

// **Styles**
const styles = StyleSheet.create({
  tabBarContainer: {
    flexDirection: 'row',
    height: 80,
    backgroundColor: 'transparent', // Transparent background
    alignItems: 'center',
    justifyContent: 'space-around', // Evenly distribute buttons
    position: 'absolute',
    bottom: 25,
    left: 0,
    right: 0,
    borderTopWidth: 1, // Add a thin line
    borderTopColor: '#ccc', // Color of the line (light gray in this case)
  },
  tabButton: {
    alignItems: 'center',
    justifyContent: 'center',
    flex: 1, // Equal space for each button
  },
});
发布评论

评论列表(0)

  1. 暂无评论