Navigating between different stackscreen in react-navigation 5 - react-native

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.

Related

asyncstorage not working in build mode in react native

in debug mode asyncstorage working perfectly fine but when build apk with this command
gradlew assembleRelease -x bundleReleaseJsAndAssets
the apk build perfectly but i want to open it show me the error appstop in my phone
any help regarding this will be very appriciated
Try this.
import AsyncStorage from '#react-native-async-storage/async-storage';
export default function App()
{
const [aldreadyLaunched, setaldreadyLaunched] = useState(true)
useEffect(() => {
AsyncStorage.getItem("alreadyLaunched").then((value) => {
if (value == "false") {
let parsedValue = JSON.parse(value)
setaldreadyLaunched(parsedValue)
}
})
},[])
return (<>
display introductory screen when the already launched state is true and when the false display login or directly main screen
</>)
}
Try this .....
const [loading, setLoading] = useState(true);
const [isFirstTimeLoad, setIsFirstTimeLoad] = useState(false);
const checkForFirstTimeLoaded = async () => {
const result = await AsyncStorage.getItem('isFirstTimeOpen');
console.log('result:', result);
if (result == null) {
setIsFirstTimeLoad(true);
setLoading(false);
} else {
setIsFirstTimeLoad(false);
setLoading(false);
}
};
if (loading)
return (
<View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
<ActivityIndicator size={'large'} color={'black'}/>
</View>
);
if (isFirstTimeLoad)
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="OnboardingScreen"
screenOptions={{
headerShown: false,
// header: () => <MainHeader />,
}}>
<Stack.Screen name="OnboardingScreen" component={OnBoardingScreen} />
<Stack.Screen name="login" component={Login} />
<Stack.Screen name="home" component={Home} />
<Stack.Screen name="register" component={Register} />
<Stack.Screen name="mobileverify" component={MobileVerify} />
<Stack.Screen name="listscreen" component={ListData} />
</Stack.Navigator>
</NavigationContainer>
);
if (!isFirstTimeLoad) return <Login />;

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>
);

Need help on navigation errors on react native app

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..

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

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!