Need help on navigation errors on react native app - react-native

I keep getting an error when trying to navigate to Home after register and login. This is the error: The action 'NAVIGATE' with payload {"name":"Home"} was not handled by any navigator. This is how I am navigating to Home after registration: navigation.navigate("Home");
Would love some advice or guidance.
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
</Stack.Navigator>
);
}
function ProfileStack() {
return (
<Stack.Navigator>
<Stack.Screen name="ProfileScreen" component={ProfileScreen} />
</Stack.Navigator>
);
}
function LeaderboardStack() {
return (
<Stack.Navigator>
<Stack.Screen name="LeaderboardScreen" component={LeaderboardScreen} />
</Stack.Navigator>
);
}
const getPage = (user) => {
if (user) {
return (
<>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: () => {
if (route.name == "Home") {
return <Entypo name="home" size={24} color="black" />;
} else if (route.name == "Leaderboard") {
return (
<MaterialIcons name="leaderboard" size={24} color="black" />
);
} else if (route.name == "Profile") {
return (
<Ionicons name="person-circle" size={24} color="black" />
);
}
},
})}
>
<Tab.Screen
name="Home"
component={HomeStack}
options={{ tabBarLabel: "Home" }}
/>
<Tab.Screen
name="Leaderboard"
component={LeaderboardStack}
options={{ tabBarLabel: "Leaderboard" }}
/>
<Tab.Screen
name="Profile"
component={ProfileStack}
options={{ tabBarLabel: "Profile" }}
/>
</Tab.Navigator>
</NavigationContainer>
</>
)
} else {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
</Stack.Navigator>
)
}
}
export default function App() {
const [loading, setLoading] = useState(true);
const [user, setUser] = useState(null);
useEffect(() => {
const usersRef = firebase.firestore().collection("users");
firebase.auth().onAuthStateChanged((user) => {
if (user) {
usersRef
.doc(user.uid)
.get()
.then((document) => {
const userData = document.data();
setLoading(false);
setUser(userData);
})
.catch((error) => {
setLoading(false);
});
} else {
setLoading(false);
}
});
}, []);
if (loading) {
return <></>;
}
return (
<NavigationContainer>
{getPage(user)}
</NavigationContainer>
);
}

There are lots of things happening here, sorry to say but your coding is mess, i can give you example how can manage it cleanly, however all i can see herr is that you tab which contains your homestack and a screen you put in stack above tab both have the same name "Home" change your stack name with homestack and try navigating there..

Related

DrawerNavigator to show tab bar all the time with every option tapped

I am trying to have a tab bar and each tab bar has its own stack navigator. Three tabs that i have are
Home
Profile
Settings
I want to show these three options in the drawer also. I have created a drawer but only tapping home shows the tab bar. I want to show tab bar just like if you press of profile tab and tab bar remains there.
Here is my code:
const HomeStackNavigator = createStackNavigator();
export const HomeNavigator = () => {
return (
<HomeStackNavigator.Navigator screenOptions={defaultNavOptions}>
<HomeStackNavigator.Screen
name="Home"
component={HomeScreen}
options={homeScreenOptions}
/>
<HomeStackNavigator.Screen
name="Details"
component={DetailsScreen}
options={detailsScreenOptions}
/>
</HomeStackNavigator.Navigator>
);
};
const ProfileStackNavigator = createStackNavigator();
export const ProfileNavigator = () => {
return (
<ProfileStackNavigator.Navigator screenOptions={defaultNavOptions}>
<ProfileStackNavigator.Screen
name="Profile"
component={ProfileScreen}
options={profileScreenOptions}
/>
<ProfileStackNavigator.Screen
name="EditProfile"
component={EditProfileScreen}
options={editProfileScreenOptions}
/>
</ProfileStackNavigator.Navigator>
);
};
const SettingsStackNavigator = createStackNavigator();
export const SettingsNavigator = () => {
return (
<SettingsStackNavigator.Navigator screenOptions={defaultNavOptions}>
<SettingsStackNavigator.Screen
name="Settings"
component={SettingsScreen}
options={settingsScreenOptions}
/>
<SettingsStackNavigator.Screen
name="AccountDetail"
component={AccountDetailsScreen}
options={accountDetailsScreenOptions}
/>
</SettingsStackNavigator.Navigator>
);
};
const HomeTabNavigator = createBottomTabNavigator();
export const TabNavigator = () => {
return (
<HomeTabNavigator.Navigator screenOptions={defaultNavOptions}>
<HomeTabNavigator.Screen
name="Home"
component={HomeNavigator}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<HomeTabNavigator.Screen
name="Profile"
component={ProfileNavigator}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="face-profile" color={color} size={size} />
),
}}
/>
<HomeTabNavigator.Screen
name="Settings"
component={SettingsNavigator}
options={{
tabBarLabel: 'Settings',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account-settings" color={color} size={size} />
),
}}
/>
</HomeTabNavigator.Navigator>
);
};
const AppDrawer = createDrawerNavigator();
export const Drawer = () => {
return(
<AppDrawer.Navigator initialRouteName="Home">
<AppDrawer.Screen name="Home" component={TabNavigator} />
<AppDrawer.Screen name="Profile" component={ProfileNavigator} />
<AppDrawer.Screen name="Settings" component={SettingsNavigator} />
</AppDrawer.Navigator>
)
};
My goal is to have tabs all the time. Tabs should hide only if we go to the detail page of any of the tabs.
You can make your TabNavigator a screen of a stack navigator which is a screen of your drawer navigator and pass a custom drawer component to your drawer navigator:
const AppDrawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
const HomeTabNavigator = createBottomTabNavigator();
export const TabNavigator = () => {
return (
<HomeTabNavigator.Navigator>
<HomeTabNavigator.Screen
name="Home"
component={HomeScreen}
options={{
tabBarLabel: 'Home',
}}
/>
<HomeTabNavigator.Screen
name="Profile"
component={ProfileScreen}
options={{
tabBarLabel: 'Profile',
}}
/>
<HomeTabNavigator.Screen
name="Settings"
component={SettingsScreen}
options={{
tabBarLabel: 'Settings',
}}
/>
</HomeTabNavigator.Navigator>
);
};
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
label="Home"
onPress={() => props.navigation.navigate('Home')}
/>
<DrawerItem
label="Profile"
onPress={() => props.navigation.navigate('Profile')}
/>
<DrawerItem
label="Settings"
onPress={() => props.navigation.navigate('Settings')}
/>
</DrawerContentScrollView>
);
}
function getHeaderTitle(route) {
return getFocusedRouteNameFromRoute(route) ?? 'Home';
}
const StackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Tabs"
component={TabNavigator}
options={({route}) => ({
headerTitle: getHeaderTitle(route),
})}
/>
<Stack.Screen name="EditProfile" component={EditProfileScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="AccountDetail" component={AccountDetailsScreen} />
</Stack.Navigator>
);
};
export const Drawer = () => {
return (
<AppDrawer.Navigator
initialRouteName="Home"
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<AppDrawer.Screen name="Stack" component={StackNavigator} />
</AppDrawer.Navigator>
);
};
function App() {
return (
<NavigationContainer>
<Drawer />
</NavigationContainer>
);
}
The screens you don't want to show the tabs for can be put inside the stack navigator outside of the tab navigator.
Sources:
https://reactnavigation.org/docs/drawer-navigator/#providing-a-custom-drawercontent.
https://reactnavigation.org/docs/screen-options-resolution/#setting-parent-screen-options-based-on-child-navigators-state.
Be sure to import DrawerItem, DrawerContentScrollView from #react-navigation/drawer and getFocusedRouteNameFromRoute from #react-navigation/native.

React navigation 5 stack navigator and drawer navigator together

Basically I am from react-navigation v4, I am familiar handling the same with SwitchNavigator as bridge, but v5 does no support for SwitchNavigator, so bit struggling to understand the below implementation.
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
function AuthenticationStack({ navigation }) {
return (
<Stack.Navigator initialRouteName="Home" screenOptions={{headerShown: false}}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Registration" component={Registration} />
</Stack.Navigator>
);
}
function UserStack({ navigation }) {
return (
<Stack.Navigator initialRouteName="Jobs" screenOptions={{headerShown: false}}>
<Stack.Screen name="Jobs" component={Profile} />
<Stack.Screen name="JobDetails" component={JobDetails} />
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Drawer.Navigator drawerContent={props => <SideBar { ...props } />}>
<Drawer.Screen name="Home" component={AuthenticationStack} />
<Drawer.Screen name="Jobs" component={UserStack} />
</Drawer.Navigator>
</NavigationContainer>
);
}
export default App;
The above code works but have some problems like,
While loading the app, initially the drawer is visible and goes hidden when the app loaded.
I do not want to have drawers for Authentication screens, If I have 2 different navigation without splitting AuthenticationStack and UserStack then I am facing problem while navigating from Login to Profile and vice versa
UPDATE 1
export default() => {
const [logged, setUser] = React.useState(false);
return (
<NavigationContainer>
{
logged
?
<DrawerScreen initialParams={{ setUser }} />
:
<AuthStackScreen initialParams={{ setUser }} />
}
</NavigationContainer>
);
}
Now in login.js, I need to update setUser to true, right? If yes how can I access setUser in my login.js file
Update 2
class Login extends Component {
fetch(login_url, {
method: "POST",
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Accept-Language': 'en-US' },
body: JSON.stringify(data)
})
.then((response) => {
const success = response.ok;
const data = response.json();
return Promise.all([success, data]);
})
.then(([success, response]) => {
var data, userInfo;
if (success) {
data = {
token: response.token,
user: response.user,
}
if(_storeUserData(response)) {
_retrieveUserData().then((userInfo) => {
this.setState({
logged: true,
userInfo: userInfo,
loading:false,
email: '',
password: ''
});
navigate('Profile');
})
.catch((error) => {
// alert(error);
});
}
}
this.setState(state_data);
})
.catch((error) => {
alert('Error:'+error);
this.setState({ loading: false});
});
}
You can create something similar to the switch navigator by conditionally rendering navigators like below.
export default function App() {
const [loggedIn, setLoggedIn] = React.useState(false);
return (
<NavigationContainer>
{loggedIn ? (
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} initialParams={{ setLoggedIn }}/>
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
) : (
<Stack.Navigator>
<Stack.Screen
name="Auth"
component={AuthScreen}
initialParams={{ setLoggedIn }}
/>
</Stack.Navigator>
)}
</NavigationContainer>
);
}
You can tryout this snack for a working example
https://snack.expo.io/#guruparan/switchsample

Navigating between different stackscreen in react-navigation 5

isSignedIn ? (
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</>
) : (
<>
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
</>
)
How can I navigate from signInScreen to HomeScreen.
You can make a context to handle the authentification flow and on your app launch check if a token or anything is already set.
const Index = () => {
const [authState, dispatch] = useAuthContext();
useEffect(() => {
const boostrapAsync = async () => {
let userToken = null;
try {
userToken = await AsyncStorage.getItem('userToken');
} catch (e) {
console.log('Restoring token failed');
}
restoreToken({ token: userToken }, dispatch);
};
boostrapAsync();
}, []);
if (authState.isLoading) {
return (
<SplashScreen />
);
}
return (
<Root>
<NavigationContainer>
<UIProvider reducer={UIReducer} initialState={initialStateUIReducer}>
{authState.userToken ? (
<UserProvider reducer={UserReducer} initialState={initialStateUserReducer}>
<AppNavigation />
</UserProvider>
) : <AuthNavigation />}
</UIProvider>
</NavigationContainer>
</Root>
);
};
export default Index;
These problems can be solved with a splash screen. I think you should collect all screens under one tag. Then, make a splash screen. After that, you can control the parameter is called isSignedIn in the SplashScreen. Then you navigate the screen which you want.

React Navigation 5.x Drawer Issue

Getting the following Issue when I use Drawer. Stack and Tab are working fine without Drawer.
Does anyone know what is going on here and can help me?
enter image description here
Here is Navigator File some Code lines:
const Stack = createStackNavigator();
const FavStack = createStackNavigator();
const FilterStack = createStackNavigator();
const Tab =
Platform.OS === "android"
? createMaterialBottomTabNavigator()
: createBottomTabNavigator();
const defaultScreenOptions = {
headerStyle: { backgroundColor: colors.primary },
headerTintColor: "white",
};
function MealsNavigator() {
return (
<Stack.Navigator screenOptions={defaultScreenOptions}>
<Stack.Screen name="Meals Categories" component={CategoriesScreen} />
<Stack.Screen name="Profile" component={CategoryMealScreen} />
<Stack.Screen name="Details" component={MealDetailsScreen} />
</Stack.Navigator>
);
}
function FavStackNavigator() {
return (
<FavStack.Navigator screenOptions={defaultScreenOptions}>
<FavStack.Screen name="Favourites" component={FavouritesScreen} />
<FavStack.Screen name="Details" component={MealDetailsScreen} />
</FavStack.Navigator>
);
}
function MealsFavTabNavigator() {
return (
<Tab.Navigator
tabBarOptions={{ activeTintColor: colors.accent }}
shifting={true}
>
<Tab.Screen
name="All"
component={MealsNavigator}
options={{
tabBarLabel: "Meals",
tabBarIcon: (tabInfo) => (
<Ionicons name="ios-restaurant" size={25} color={tabInfo.color} />
),
tabBarColor: colors.primary,
}}
/>
<Tab.Screen
name="Favourites"
component={FavStackNavigator}
options={{
tabBarIcon: (tabInfo) => (
<Ionicons name="ios-star" size={25} color={tabInfo.color} />
),
tabBarColor: colors.accent,
}}
/>
</Tab.Navigator>
);
}
function FilterStackNavigator() {
return (
<FilterStack.Navigator>
<FilterStack.Screen name="Filters" component={FilterScreen} />
</FilterStack.Navigator>
);
}
const Drawer = createDrawerNavigator();
function MenuNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="MealFavs" component={MealsFavTabNavigator} />
<Drawer.Screen name="Filters" component={FilterStackNavigator} />
</Drawer.Navigator>
);
}
export default MenuNavigator;
Here is App.js few Code lines:
export default function App() {
const [fontLoaded, setFontLoaded] = useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => setFontLoaded(true)}
onError={(err) => console.log(err)}
/>
);
}
return <NavigationContainer><MealsNavigator /></NavigationContainer>
}
Code is not giving error without Drawer, It is working exactly fine with Stack and Tab Navigators!

How to pop on the top of stack once the tab is changed?

I have a tab bar with 4 tabs. Each of them have a stack navigator. I want to pop to Top once the tab is switched? I have an inkling it has to do with defaultNavigationOptions. Please suggest me something.
I used this:
import {StackActions} from 'react-navigation'
defaultNavigationOptions: ({ navigation }) => ({
tabBarOnPress: ({ navigation, defaultHandler }) => {
const { routeName } = navigation.state
navigation.dispatch(StackActions.popToTop());
defaultHandler()
},
})
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
const SettingsStack = createStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen
name="Settings"
component={SettingsStackScreen}
listeners={({ navigation, route }) => ({
tabPress: e => {
// navigation.popToTop();
navigation.navigate(route.name);
},
})}
/>
</Tab.Navigator>
</NavigationContainer>
);
}