React navigation : FragmentManager is already executing transanctions - react-native

I was using BottomTabNavigation to create tabs navigation in react native with nested Stack navigation, but when I want to implement the same logic with createMaterialTopTabNavigator, I get this error. here's the code :
const Stack = createNativeStackNavigator()
const TopTab = createMaterialTopTabNavigator()
const HomeStack = () => {
return <Stack.Navigator>
<Stack.Screen name="Home" component={Home} options={options} />
<Stack.Screen name="TodoDetail" component={TodoDetail} />
</Stack.Navigator>
}
export default function App() {
return (
<NavigationContainer>
<TopTab.Navigator>
<TopTab.Screen name='Home' component={HomeStack} />
<TopTab.Screen name='About' component={About} />
</TopTab.Navigator>
</NavigationContainer>
)
}
here is the error in the device :

The problem is not with the definition of TopTab, but the current implementation leads to the issue.
The TopTab navigation must be in a Stack.Screen. forget about the BottomTabNavigation, it uses a different approach to show the screens.
So You must use TopTabNavigation inside of a screen
Just for an example with the current implementation:
const Stack = createNativeStackNavigator()
const TopTab = createMaterialTopTabNavigator()
const topBarStack = () => {
return (
<TopTab.Navigator>
<TopTab.Screen name='first-tab' component={firstTab} />
<TopTab.Screen name='second-tab' component={secondTab} />
</TopTab.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={topBarStack} options={options} />
<Stack.Screen name="TodoDetail" component={TodoDetail} />
</Stack.Navigator>
</NavigationContainer>
)
}

Related

Navigate between two stack Navigators after login in react native

This is my first stack
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Home" component={MainScreen} />
<Stack.Screen name="Schools" component={SchoolsScreen} />
<Stack.Screen name="Setting" component={SettingScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Saved" component={SavedData} />
<Stack.Screen name="Profile2" component={Profile2} />
<Stack.Screen name="SchoolDetails" component={SchoolDetailsScreen} />
<Stack.Screen name="Bottom" component={BottomTab} />
</Stack.Navigator>
</NavigationContainer>
This is my second stack
<NavigationContainer>
<Stack.Navigator
initialRouteName="Login"
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Login" component={AuthLogin} />
<Stack.Screen name="Register" component={AuthRegister} />
<Stack.Screen name="Forget" component={ForgetPassword} />
</Stack.Navigator>
</NavigationContainer>
THis is my app.js file
const [auth, setAuth] = useState(false);
useEffect(() => {
(async () => {
const value = await AsyncStorage.getItem("isLoggedin");
console.log(value);
setAuth(value);
})();
}, []);
return (
<SafeAreaView style={{ flex: 1 }}>
<NativeBaseProvider config={config}>
{auth == "true" ? <InsideStack /> : <OutsideStack />}
</NativeBaseProvider>
</SafeAreaView>
);
}
I want to navigate to home screen from login screen , after function call
// navigation.push("Home");
const storeData = async (value) => {
try {
await AsyncStorage.setItem("isLoggedin", JSON.stringify(true));
} catch (e) {
// saving error
}
};
storeData();
navigation.push("Home");
}}
But i got error:
Do you have a screen named 'Home'?
this is the simple code for this. you have to use redux or context api for gloal state management. here is a min example ;
import {NavigationContainer} from '#react-navigation/native';
import React from 'react';
import {useDispatch, useSelector} from 'react-redux';
import {GetUserContacts} from '../logic/getcontact';
import {setContacts} from '../store/actions/ContactActions';
import AuthNavigation from './AuthNavigation';
import RootNavigation from './RootNavigation';
const AppContainer = () => {
const {is_logged_in} = useSelector(state => state.persistedReducer);
const dispatch = useDispatch();
if (is_logged_in) {
GetUserContacts('PK').then(data => {
dispatch(setContacts(data));
});
}
return (
<NavigationContainer>
{is_logged_in ? <RootNavigation /> : <AuthNavigation />}
</NavigationContainer>
);
};
export default AppContainer;
after user logged in you have to make that is_logged_in true. so the navigator changes itself. you will have to persist this so when application restart the user dont need to login again

A navigator can only contain 'Screen', 'Group' or 'React.Fragment' as its direct children (found 'BottomTap')

I was trying to use TabNavigator in expo, but I have a problem, I have created a component where I have all the routes in a Tab, and in the other component I am only importing it.
in this component I have all the routes of my app:
const AppRouter = () => {
const Stack = createNativeStackNavigator();
const { user } = useContext(AuthContext);
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
{!user ? (
<>
<Stack.Screen name="login" component={Login} />
<Stack.Screen name="register" component={Register} />
</>
) : (
<>
<BottomTap />
</>
)}
</Stack.Navigator>
);
};
and in this component I am creating the Tabs with their routes:
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import Home from "../../screens/Home";
const Tab = createBottomTabNavigator();
const BottomTap = () => {
return (
<Tab.Navigator>
<Tab.Screen name="home" component={Home} />
</Tab.Navigator>
);
};
export default BottomTap;
Like the error says, navigators can only contain other navigators - not even custom components that contain only navigators. You can solve this by putting your tab navigator component inside a screen.
Instead of
<BottomTap />
Use
<Stack.Screen name="bottomTap" component={BottomTap} />
You can read more about this in the "Nesting Navigators" section of the React Navigation docs: https://reactnavigation.org/docs/nesting-navigators/
You are adding a React component inside of a navigator instead of 'Screen', 'Group' or 'React.Fragment'. The correct way to add a navigator inside another is:
...
{!user ? (
<>
<Stack.Screen name="login" component={Login} />
<Stack.Screen name="register" component={Register} />
</>
) : (
<>
<Stack.Screen name="bottomTap" component={BottomTap} />
</>
)}
...

Using two Navigators in an app React native

Trying to use bar Navigation and drawer navigator in the same app, and now sure how to make it work.
So currently In the App.js I have a "NavigationContainer", and inside I have a "BarNavigator". whcih works fine, then I wanna add a "DrawerNavigator" inside the "NavigationContainer" then I got an error "Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app"
then i found this link doing exactly what i wanted ( showing at the end of the page ) and apply what he is doing. still got the same error, then I removed the "BarNavigator" which is the working one, and test out if DrawerNavigator got error, and yes. even got error with the DrawerNavigator only. and here is the code.
App.js
const App = () => {
return (
<NavigationContainer>
//<HomeStackNavigator />
<DrawerNavigator />
</NavigationContainer>
);
};
export default App;
DrawerNavigator.js
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={navigation_bar} />
{/* <Drawer.Screen name="Notifications" component={Ivestment} /> */}
</Drawer.Navigator>
</NavigationContainer>
);
};
export default DrawerNavigator;
Navigator.js
const Stack = createStackNavigator();
const screenOptionStyle = {
headerShown: false,
};
const HomeStackNavigator = () => {
return (
<Stack.Navigator screenOptions={screenOptionStyle}>
<Stack.Screen name="Home" component={BottomTabNavigator} />
<Stack.Screen name="Detail" component={Detail} />
</Stack.Navigator>
);
};
export default HomeStackNavigator;
You are doing it wrong.
You should have only 1 "NavigationContainer" and the navigators should be nested, i.e. one inside of another (parent-child not siblings).
It should look something like this:
App.js
const App = () => {
return (
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
);
};
export default App;
DrawerNavigator.js
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeTabNavigator} />
<Drawer.Screen name="OtherScreen" component={OtherScreen} />
</Drawer.Navigator>
);
};
export default DrawerNavigator;
TabNavigator.js
const Tab = createTabNavigator();
const screenOptionStyle = {
headerShown: false,
};
const HomeTabNavigator = () => {
return (
<Tab.Navigator screenOptions={screenOptionStyle}>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Detail" component={Detail} />
</Tab.Navigator>
);
};
export default HomeTabNavigator;
Might be easier to look at it bottom-top as well.

React Native Tab nested into Stack navigation v5 - best practice to update header

I am trying to understand what's the best approach to nested React Native Navigation v5.
I have a TabNavigation nested into a Stack.Navigator as follow:
const MainNavigation = () => {
return (
<SafeAreaProvider>
<NavigationContainer>
<StatusBar barStyle="light-content" />
<Stack.Navigator screenOptions={navStackOptions} >
<FirstListStack.Screen name="FirstListStack" component={TabNavigation} options={FirstNavOpt} />
<FirstListStack.Screen name="AnotherView" component={AnotherView} options={AnotherViewNavOpt} />
<SecondListStack.Screen name="SecondListStack" component={TabNavigation} options={SecondNavOpt} />
<ThirdListStack.Screen name="ThirdListStack" component={TabNavigation} options={ThirdNavOpt} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
function TabNavigation() {
return (
<Tab.Navigator
initialRouteName="TabOne"
>
<Tab.Screen name="TabOne" component={TabOne} options={navTabOptions} />
<Tab.Screen name="TabTwo" component={TabTwo} options={navTabOptions} />
<Tab.Screen name="TabThree" component={TabThree} options={navTabOptions} />
</Tab.Navigator>
);
}
};
export default MainNavigation;
Now, when switching between the tabs, the stack navigation header does not get updated.
What's the best approach to access the state of the Stack Navigation and update its state? In particular to update the header buttons?
Let me know if my question is unclear.
Many thanks.
I found a solution, but I am not sure is a good practice.
I changed the logic of the Navigation moving the Tab Nav as parent and the Stack Nav as child.
const Tab = createBottomTabNavigator();
const FirstListStack = createStackNavigator();
const SecondListStack = createStackNavigator();
const ThirdListStack = createStackNavigator();
const MainNavigation = () => {
const navTabOptions = ({ route }) => ({
tabBarVisible: isTabBarVisible(route)
});
return (
<SafeAreaProvider>
<NavigationContainer>
<StatusBar barStyle="light-content" />
<Tab.Navigator>
<Tab.Screen name="First" component={FirstListStackScreen} options={navTabOptions} />
<Tab.Screen name="Second" component={SecondListStackScreen} options={navTabOptions} />
<Tab.Screen name="Third" component={ThirdListStackScreen} options={navTabOptions} />
</Tab.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
function isTabBarVisible(route) {
// Check here if the route.state is not undefined
// and based on the route return true or false
// to show or hide the tab bar
}
function FirstListStackScreen() {
return (
<FirstListStack.Navigator>
<FirstListStack.Screen name="First" component={} />
</FirstListStack.Navigator>
);
}
function SecondListStackScreen() {
return (
<SecondListStack.Navigator>
<SecondListStack.Screen name="Second" component={} />
</SecondListStack.Navigator>
);
}
function ThirdListStackScreen() {
return (
<ThirdListStack.Navigator>
<ThirdListStack.Screen name="Third" component={} />
</ThirdListStack.Navigator>
);
}
};
export default MainNavigation;
Please post any better solution to this.
Thanks

React navigation 5 - header is not shown

Trying to update my app to react navigation 5 and been confronting some issues.
First of all, the header does not show up. Snips from the code:
[from App.js]
const Tab = createBottomTabNavigator();
function App() {
return (
<NavigationContainer>
<Tab.Navigator >
<Tab.Screen name="Home" component={HomeScreen} options={{ title:'some title' }}/>
<Tab.Screen name="Upload" component={UploadScreen} />
<Tab.Screen name="Find" component={FindScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
export default App;
and the style of the current screen:
<View style={{flex:1, flexDirection:'column',justifyContent:'space-between'}}>
Here is a screenshot of the app on an Android emulator (and it looks the same on my phone):
As you can see, the header is not shown, the tab navgiation does not right, and so are the buttons (something changed about their background). I did not change anything in the app besides upgrading to react-navigation 5..
Thanks for the help!
Tab navigators do not have header support. You have to wrap your tab navigator inside a stack navigator.
import { createStackNavigator } from "#react-navigation/stack";
// ... other imports
export const App = () => {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
const Stack = createStackNavigator();
const StackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Tabs" component={TabNavigator} />
</Stack.Navigator>
);
}
const Tab = createTabNavigator();
const TabNavigator = () => {
return (
<Tab.Navigator >
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Upload" component={UploadScreen} />
<Tab.Screen name="Find" component={FindScreen} />
</Tab.Navigator>
);
}