Mobx update token and Navigate to the Auth Screen - react-native

I am new with Mobx and I want to store token after login screen and navigate to dashboard which is behind the Auth Navigator.
const AppStack = () => {
const { getToken } = useTokenStore()
const [userToken, setUserToken] = React.useState(false)
useEffect(() => {
console.log("<<<<< IS LOGGED IN STATE >>>>>>")
console.log(userToken)
console.log("<<<<< IS LOGGED IN STATE >>>>>>")
setUserToken(getToken())
console.log("<<<<< NEW TOKEN IN STATE >>>>>>")
console.log(userToken)
console.log("<<<<< NEW TOKEN IN STATE >>>>>>")
}, [userToken])
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="login"
>
{!userToken ? (
<>
<Stack.Screen name="login" component={LoginScreen} />
<Stack.Screen name="signup" component={SignupScreen} />
<Stack.Screen name="resetpassword" component={ResetPasswordScreen} />
<Stack.Screen name="demo" component={DemoScreen} />
<Stack.Screen name="demoList" component={DemoListScreen} />
<Stack.Screen name="welcome" component={WelcomeScreen} />
</>
) : (
<>
<Stack.Screen name="dashboard" component={DashboardScreen} />
</>
)}
</Stack.Navigator>
)
}
I get the error ERROR The action 'NAVIGATE' with payload {"name":"dashboard"} was not handled by any navigator. Please advice me on the best way to change the value of the mobx stored data in realtime and navigate

Related

"Tried to Synchronously call anonymous function from a different thread."

I have this issue whenever I toggle the drawer on my screen. I want to login and then go to Home page where there will be a drawer. But I don't know where the issue is.
PS: I have Expo managed project and I already installed react-native-gesture-handler and react-native-reanimated.
This is the code for navigating :
const Stack = createNativeStackNavigator();
const Drawer = createDrawerNavigator();
const DrawerComponent = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Dashboard" component={Test} />
<Drawer.Screen name="Reset" component={Reset} />
</Drawer.Navigator>
);
};
const Navigation = () => {
return (
<Stack.Navigator>
<Stack.Screen name="StartUp" component={StartUp} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Reset" component={Reset} />
<Stack.Screen name="DrawerComponent" component={DrawerComponent} options={{title: "drawer"}}/>
</Stack.Navigator>
);
};
export default Navigation;

react native navigation between screens

I'm trying to use reactnavigation.org library and I have some issue with that. I have two types of navigation screens. Two screens are a registration and authorization. And others are regular app screens. Problem is that I can't render parent component App.js or other functionality to reload app from child component and thus change my screens block. Navigation between screens Run, History, Profile, OtherRunners works fine. Navigation between screens Main and Enter works fine. But if I need navigate from Run to Main, or from Enter to Run there is a problem.
App.js
const App = () => {
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
const [loggedIn, setLoggedIn] = useState(false)
async function getUserEmail(){
if(await AsyncStorage.getItem('#email')){
setLoggedIn(true)
}else{
setLoggedIn(false)
}
}
getUserEmail()
function MenuDraw(){
return(
<Drawer.Navigator
drawerContentOptions={}
drawerType={}
drawerStyle={{}}
>
<Drawer.Screen
name="Run"
component={Run}
options={}
/>
<Drawer.Screen
name="History"
component={History}
options={}
/>
<Drawer.Screen
name="Profile"
component={Profile}
options={}
/>
<Drawer.Screen
name="OtherRunners"
component={OtherRunners}
options={}
/>
<Drawer.Screen
name="LogOut"
component={Run}
initialParams={{action: 'logout'}}
options={}
/>
</Drawer.Navigator>
)
}
function MyDrawer(){
if(loggedIn){
return(
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"MenuDraw"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="Details" component={Details}/>
</Stack.Navigator>
)
}else{
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"Main"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw} />
<Stack.Screen name="Details" component={Details} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}
}
return(
<NavigationContainer>
<MyDrawer/>
</NavigationContainer>
)
}
export default App;
I tried using reload app tools, but those wasn't help me. They are wasn't working. In this section of code which is below. On the Run screen.
Run.js
const Run = ({navigation,route}) => {
const clearStorage = async () => {
await AsyncStorage.clear()
}
if(route.params){
if(route.params.action === 'logout'){
clearStorage()
navigation.navigate("Main", {})
}
}
}
export default Run;
I'm trying to logout by cleaning the storage and navigate to Main screen. But it's not working on release mode. I've tried this, which is below.
App.js
function MyDrawer(){
if(loggedIn){
return(
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"MenuDraw"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="Details" component={Details}/>
++++ <Stack.Screen name="Main" component={Main} />
++++ <Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}else{
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"Main"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw} />
<Stack.Screen name="Details" component={Details} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}
}
Not working either way. How can I fix it? Can I render App.js component from child screens? Or perhaps I should create two screen blocks line
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="MenuRegister" component={MenuRegister}/>
and put all my screens by belongings to match section?
I need to logout from this section:
App.js
some code
<Drawer.Screen
name="LogOut"
component={Run}
initialParams={{action: 'logout'}}
options={}
/>
</Drawer.Navigator>
some code
Did you try using useEffect hook, to get on the road? :-)
useEffect(() => {
const getUserEmail = async () => {
if(await AsyncStorage.getItem('#email')){
setLoggedIn(true)
}else{
setLoggedIn(false)
}
};
getUserEmail();
}, []);

React-navigation redirect from a signIn screen

I have 3 screens, Home.js, SignIn.js and CreateElement.js. People must be logged in to use CreateElement.js. So when some user is on Home and wants to use CreateElement the screen should redirect them to SignIn.js and then when the user is logged SignIn should continue the flow and redirect them to CreateElement.js.
My code doesn't work and it is the following
return (
<NavigationContainer linking={Linking}>
<AuthChecker>
<LanguageHandler>
<Stack.Navigator headerMode="none" >
<Stack.Screen name="Home" component={HomeScreen} />
{loggedIn
? <>
<Stack.Screen name="Create" component={CreateElementScreen} />
</>
: <>
<Stack.Screen name="SignIn" component={SignInScreen} />
</>
}
</Stack.Navigator>
</LanguageHandler>
</AuthChecker>
</NavigationContainer>
);
}
loggedIn is in the redux store.
Home.js has:
if (loggedIn)
navigate('Create')
else
navigate('SignIn')
and SignIn only change loggedIn to TRUE.
My first solution was create a private component like this one.
// #Vendors
const PrivateRoute = ({ loggedIn, children}) => {
const { navigate } = useNavigation();
useLayoutEffect(() => {
if (!loggedIn)
navigate('SignIn');
console.log('Component is mounted in the DOM');
}, []);
if (loggedIn)
return {children} //In This case <CreateElement/>
else
return <></>
}
const mapStateToProps = ({ auth }) => ({
loggedIn: auth.loggedIn
});
export default connect(mapStateToProps)(PrivateRoute);
My solution work on Android and IOS but when I use react-native-web, the code work but if I enter by URL to CreateElement the privateElement doesn't redirect to me
Any suggestion?
Have you checked whether the loggedIn variable is updated every time after the data is updated?
You might need a useState hook for updating the component.
Something like this:
const [isAuthenticated] = useState(loggedIn);
return (
<NavigationContainer linking={Linking}>
<AuthChecker>
<LanguageHandler>
<Stack.Navigator headerMode="none">
<Stack.Screen name="Home" component={HomeScreen} />
{isAuthenticated ? (
<>
<Stack.Screen name="Create" component={CreateElementScreen} />
</>
) : (
<>
<Stack.Screen name="SignIn" component={SignInScreen} />
</>
)}
</Stack.Navigator>
</LanguageHandler>
</AuthChecker>
</NavigationContainer>
);

ReactNative- Tab Navigator Inside Stack Navigator

Need to Show Tabs For Home Module after Signup Module
using React-navigation
Working Code with Only Stack Screens
const Stack = createStackNavigator();
const Bottom = createBottomTabNavigator();
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Welcome" headerMode='none' >
<Stack.Screen name="Welcome" component={WelcomeScreen}
options={{
title: '',
headerBackTitleVisible: false,
headerBackTitle: '',
headerShown: true
}}
/>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Signup" component={SignupScreen} />
<Stack.Screen name="ResetPassword" component={ResetPasswordScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Need to show Tab from SigninScreen Button
Tab 1: Dashboard:
Tab 2: Profile
Tried Code:
<Bottom.Navigator initialRouteName="Dashboard" >
<Bottom.Screen name="Dashboard" component={TabDashboard} />
<Bottom.Screen name="Profile" component={TabProfile} />
</Bottom.Navigator>
Now I need to combine these two block of codes so I can navigate to Tabs
Tab screen will have further navigations
The idea would be to wrap the tabs screen inside component and add it to the stack conditionally.
const HomeScreen = () =>{
return (
<Bottom.Navigator initialRouteName="Dashboard" >
<Bottom.Screen name="Dashboard" component={TabDashboard} />
<Bottom.Screen name="Profile" component={TabProfile} />
</Bottom.Navigator>
);
}
Your stack should change as below
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Welcome" headerMode='none' >
{
this.state.isSignedIn ? (
<>
<Stack.Screen name="Welcome" component={WelcomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Signup" component={SignupScreen} />
<Stack.Screen name="ResetPassword" component={ResetPasswordScreen} />
</>
) : (
<>
<Stack.Screen name="ResetPassword" component={HomeScreen} />
</>
)
}
</Stack.Navigator>
</NavigationContainer>
);
}
IsSignedIn can be the state variable or a variable that you store the logged in status
You can refer the authentication flows
https://reactnavigation.org/docs/auth-flow

Navigation can't find screen if states condition is in Stack.Navigator

When I want to navigate from Home screen to Login screen I get error:
ExceptionsManager.js:173 The action 'NAVIGATE' with payload {"name":"Login"} was not handled by any navigator. Do you have a screen named 'Login'?
routes.js:
import LoginScreen from '../screens/login/login';
import HomeScreen from '../screens/home/home';
const Stack = createStackNavigator();
const App = () => {
const [userToken, setuserToken] = React.useState(null);
React.useEffect(() => {
_bootstrapAsync = async () => {
const token = await AsyncStorage.getItem('token');
if (userToken) {
setuserToken(token)
}
}
_bootstrapAsync()
})
return (
<NavigationContainer>
<Stack.Navigator>
{userToken == null ? (
<Stack.Screen name="Login" component={LoginScreen} />
) : (
<Stack.Screen name="Home" component={HomeScreen} />
)}
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
home.js:
import { AsyncStorage } from 'react-native';
import { Container, Text, Button, Content } from 'native-base';
const HomeScreen = (props) => {
const { navigation } = props
handleLogout = async () => {
await AsyncStorage.clear();
navigation.navigate('Login');
};
return (
<Container>
<Content>
<Button full onPress={handleLogout}>
<Text>Log Out</Text>
</Button>
</Content>
</Container>
);
}
export default HomeScreen;
If in routes.js I remove userToken states condition, and in Stack.Navigator is only:
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
I can successfully navigate from Home to Login screen.
But this approach is not good, because I need to have checking if token is present in Storage.
How can I solve this issue?
You will not able to find the Login route until your condition is true, that's the reason you are not able to find the Login route
change
{userToken == null ? (
<Stack.Screen name="Login" component={LoginScreen} />
) : (
<Stack.Screen name="Home" component={HomeScreen} />
)}
to
{userToken == null ? (
<Stack.Screen name="Login" component={LoginScreen} />
) : (
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
)}
Hope this helps!