I am fairly new to react-native but I have been able to make a login with authentication using firebase. Alongside this, I have used a drawer for further navigation. However, when a user is logged in I want them to be able to logout via a button on that drawer. Currently, when I click it is it doing nothing...
I have tried changing to the this.logout function to this.logout() which reaches the console.log("here) statement but then returns an undefined error. I have also played around with the bindings but with no results.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
authenticated: false,
}
this.logout = this.logout.bind(this)
};
componentDidMount() {
firebaseConfig.auth().onAuthStateChanged((authenticated) => {
authenticated ? this.setState(() => ({
authenticated: true,
})) : this.setState(() => ({
authenticated: false,
}));
});
}
//Logout of firebase and navigate to login screen
logout = () => {
console.log("here")
firebaseConfig.auth().signOut()
.then(() => this.props.navigation.navigate('Login'))
.catch((err) => {
console.log(err)
});
};
render() {
//const {currentUser} = this.state
return (
<Application/>
)
}
}
const DrawerComponents = (props) =>
<SafeAreaView style={styles.safeArea}>
<View style={styles.logo}>
</View>
<ScrollView>
<DrawerItems{...props}/>
<View style={{flex: 1}}>
<Button title="Logout" onPress={this.logout}/>
</View>
</ScrollView>
</SafeAreaView>
const TabNavigator = createDrawerNavigator({
Home: {screen: Homepage},
Profile: {screen: Profile},
Login: {
screen: Login,
navigationOptions: ({navigation}) => {
return {
drawerLabel: () => null,
drawerLockMode: 'locked-closed'
}
}
},
SignUp: {
screen: SignUp,
navigationOptions: ({navigation}) => {
return {
drawerLabel: () => null,
drawerLockMode: 'locked-closed'
}
}
},
Loading: {
screen: Loading,
navigationOptions: ({navigation}) => {
return {
drawerLabel: () => null,
drawerLockMode: 'locked-closed'
}
}
},
},
{
headerMode: null,
contentComponent: DrawerComponents,
drawerWidth: WIDTH,
drawerPosition: "right",
initialRouteName: 'Home',
contentOptions: {
activeTintColor: "orange"
}
});
const Application = createAppContainer(TabNavigator)
});
I am expecting that upon clicking logout, the currently logged in user on firebase is signed out and then is redirected to the login screen.
Related
I have managed to get my login authentification working, but I am having an issue with the conditional navigator in App.js. If I log in using the LoginStackNavigator, I then need to refresh the app to be able to use the DrawerNavigator. I would like it so that as soon as I log in, App.js realises this, and takes me to the drawer navigator.
I've tried to use the Context API but it isn't working. What am I doing wrong?
Here is my AppContext.js
import { createContext } from "react";
const AppContext = createContext({
isloggedIn: {},
setLoggedIn: () => {},
});
export default AppContext;
Here is my App.js:
import AppContext from "./src/Component/AppContext";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isloggedIn: false,
};
this.loginStatusCheck();
}
loginStatusCheck = async () => {
const userToken = await AsyncStorage.getItem("#storage_Key");
if (userToken) {
this.setState({ isloggedIn: true });
} else {
this.setState({ isloggedIn: false });
}
};
render() {
return (
<AppContext.Provider
value={{
isloggedIn: this.state.isloggedIn,
setLoggedIn: this.setLoggedIn,
}}
>
<NavigationContainer>
{this.state.isloggedIn ? (
<DrawerNavigator />
) : (
<LoginStackNavigator />
)}
</NavigationContainer>
</AppContext.Provider>
);
}
}
And here is my LoginScreen.js:
import AppContext from "../../Component/AppContext";
const LoginCall = () => {
const { setLoggedIn } = useContext(AppContext);
return setLoggedIn(true);
};
export default class LoginScreen extends Component {
login = async () => {
const { email, password, confirmpassword } = this.state;
console.log(email);
axios
.post("http://127.0.0.1:8002/rest-auth/login/", {
username: "username",
email: "default#email.com",
password: "password",
})
.then((response) => {
console.log(response.data.key);
this.storeKey(response.data.key);
LoginCall;
})
//.then(this.props.navigation.navigate("HomeScreen"))
.catch((error) => {
console.log(error);
});
};
storeKey = async (value) => {
try {
await AsyncStorage.setItem("#storage_Key", value);
} catch (e) {
console.log("error" + e);
} finally {
console.log("done");
}
};
render() {
return (
<View
style={{
backgroundColor: "#fff",
paddingTop: 40,
alignItems: "center",
flex: 1,
}}
>
<TouchableOpacity onPress={() => this.login()}>
<Text>Login</Text>
</TouchableOpacity>
</View>
);
}
}
I think its because you're not importing axios on LoginSreen.
Try to add import axios from 'axios' with others importations
I have an application where a token get stored once the users open the app for the first time, and I need to check for that token when the app starts and create the navigator,
Approach 1
const getValue = async () => {
try {
value = await AsyncStorage.getItem('token').then((value) =>{
console.log(value)
})
} catch (error) {
console.log(error.message);
}
};
if (token != undefined) {
stackNavigator = createStackNavigator({
Products: Products,
Product: Product
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
})
} else {
stackNavigator = createStackNavigator({
Home:Home,
Products: Products,
Product: Product
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
})
}
In the first approach, it always renders the home screen even if the token is stored in the application
Second approach
const getValue = async () => {
try {
value = await AsyncStorage.getItem('token').then((value) =>{
if(value == null){
stackNavigator = createStackNavigator({
Home:Home,
Products: Products,
Product: Product
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
})
}else{
stackNavigator = createStackNavigator({
Products: Products,
Product: Product
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
})
}
})
} catch (error) {
console.log(error.message);
}
};
This approach throws Cannot read property of router undefined
Is there a way to get this to work?
Navigation.js
export const getValue = async () => {
let VALUE;
try {
await AsyncStorage.getItem('token')
.then((value) =>{
if(value == null){
VALUE = stackNavigator = createStackNavigator({
Home:Home,
Products: Products,
Product: Product
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
})
}else{
VALUE = stackNavigator = createStackNavigator({
Products: Products,
Product: Product
}, {
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
})
}
})
} catch (error) {
console.log(error.message);
}
return VALUE;
};
App.js
import { getValue } from './layout/navigation/Navigation';
let Navigation = createAppContainer(getValue());
class App extends React.Component {
render() {
return (<Navigation/>)
}
}
Create Routing
stackNavigator = createStackNavigator({
Home:Home,
Products: Products,
Product: Product,
Login : Login
},
{
headerMode: 'none',
initialRouteName : 'Home', // provide initial route : app will open with Home page
navigationOptions: {
headerVisible: false
},
})
// Export it with createAppContainer
export default createAppContainer(stackNavigator);
Import it to your App.js and use it as <Router/>
import Router from 'Application/navigation/routes';
Now what you can do is when user going to login then store their token to AsyncStorage and then redirect to home page.
In your home page you can add your token is exist or not code in mount lifecycle if you are not getting your token from storage then you can navigate your route to login screen.
I have a react native component and i am trying to connect that component to react-redux through connect, but i am getting error stating the getScreen() defined for route didnt returned a valid screen.
But when i remove connect from the component it works fine in the navigator.But when i use connect , i am getting the error.
Below is the component
class LoginScreen extends Component {
componentDidMount() {
// this.props.login();
console.log(this.props.auth, 'this is staet')
}
render() {
return (
<Box f={1}>
<Box f={1}>
<ImageBackground source={images.bg} style={styles.container}>
<Box bg="white" f={0.5} w="100%" p="lg" style={styles.abs}>
<Text size={'2xl'}>
OTP has been
</Text>
<Text size={'2xl'}>
send to your mobile
</Text>
<Text size={'md'}>
Verify your mobile number
</Text>
</Box>
</ImageBackground>
</Box>
</Box>
);
}
}
export default
connect(
mapStateToProps, {
login
}
)
(LoginScreen);
And here is the navigator file
const AuthNavigator = createStackNavigator({
Login: {
getScreen: () => require('./LoginScreen').default
}
}, {
navigationOptions: {
header: null
}
})
const TabNavigator = createBottomTabNavigator({
Home: {
getScreen: () => require('./HomeScreen').default
}
})
const MainNavigator = createStackNavigator({
Tab: TabNavigator
});
const AppNavigator = createSwitchNavigator({
Splash: {
getScreen: () => require('./SplashScreen').default
},
Auth: AuthNavigator,
Main: MainNavigator
}, {
initialRouteName: 'Splash'
});
try this code.
import LoginScreen from './screens/LoginScreen'
const AuthNavigator = createStackNavigator({
Login: {
screen: LoginScreen,
}
}, {
navigationOptions: {
header: null
}
})
I am using react-navigation, I want to open a drawer from MyProfile screen, having the options to go to EditProfile screen and Settings screen. But I can't figure out how to open a drawer when I click on MyProfile's header button.
App.js:
const MyProfileStack = createStackNavigator({
MyProfile: {
screen: profile,
navigationOptions: ({navigation}) => {
return {
title: "My Profile",
headerRight: (
<Icon type="evilicon" name="navicon" size={40}
onPress={() => navigation.dispatch(DrawerActions.openDrawer())}/>
)
};
}
}
})
const DrawerStack = createDrawerNavigator({
Edit: { screen: EditProfileStack }
Settings: { screen: SettingsStack }
})
const EditProfileStack = createStackNavigator({
EditProfile: {
screen: editProfile,
navigationOptions: ({navigation}) => {
return {
title: "Edit Profile",
headerLeft: (
<Icon type="evilicon" name="chevron-left" size={50}
onPress={() => navigation.navigate("MyProfile")}/>
)
};
}
}
});
const TabStack = createBottomTabNavigator({
Feed: { screen: FeedStack },
Profile: { screen: MyProfileStack },
});
const MainStack = createSwitchNavigator(
{
Home: TabStack,
Drawer: DrawerStack
},
{
initialRouteName: 'Home'
}
);
const AppContainer = createAppContainer(MainStack);
Solution
You need to put your MyProfileStack in DrawerStack as below.
const DrawerStack = createDrawerNavigator({
MyProfile: { screen: MyProfileStack }
Edit: { screen: EditProfileStack }
Settings: { screen: SettingsStack }
})
const TabStack = createBottomTabNavigator({
Feed: { screen: FeedStack },
Profile: { screen: DrawerStack },
});
const AppContainer = createAppContainer(MainStack);
You can use various combination.
Why?
SwitchNavigator resign other Screens when you switch to another one. So you cannot call drawer from the screen already resigned.
p.s: You can use navigation events if you want to refresh your screen when change the screen. Use onWillFocus.
I have two navigators one is stackNavigator and another is drawerNavigator.
what I want to do is dispatch an action and login is successfull and redirect the user to drawer navigator. I have used react-navigation.
What I have done is I am dispatching the action login success in saga.
Using NavigationActions.navigate({ routeName: 'drawerStack' }) to dispatch the action.
The action dispatches successfully but it doesn't navigate to drawerNavigator as shown in the picture below. What am I doing wrong?
saga.js
function* watchLoginRequest() {
while (true) {
const { state } = yield take(LOGIN_REQUEST);
try {
const payload = {
state
};
const response = yield call(loginCall, payload);
yield put(loginSuccess(response));
yield setUser(response.user);
yield put(NavigationActions.navigate({ routeName: 'drawerStack' }));
} catch (err) {
yield put(loginFailure(err.status));
}
}
}
drawerNavigation.js
// drawer stack
const DrawerStack = DrawerNavigator({
testComponent: { screen: TestComponent },
});
const DrawerNav = StackNavigator({
drawerStack: { screen: DrawerStack }
}, {
headerMode: 'float',
navigationOptions: ({ navigation }) => ({
headerStyle: { backgroundColor: 'green' },
title: 'Logged In to your app!',
headerLeft: <Text onPress={() => navigation.navigate('DrawerOpen')}>Menu</Text>
})
});
export default DrawerNav;
loginNavigation.js
// login stack
const LoginStack = StackNavigator({
startScreen: { screen: StartScreen },
loginScreen: { screen: LoginScreen },
personalInformation: { screen: PersonalInformation },
vehicleInformation: { screen: VehicleInformation },
availability: { screen: Availability },
selectRegisteration: { screen: SelectRegisteration },
serviceAddress: { screen: ServiceAddress },
}, {
headerMode: 'none',
transitionConfig: TransitionConfiguration
});
export default LoginStack;
ReduxNavigation.js
class ReduxNavigation extends React.Component {
constructor(props) {
super(props);
const { dispatch, nav } = props;
const navigation = ReactNavigation.addNavigationHelpers({
dispatch,
state: nav
});
this.state = {
loggedInStatus: false,
checkedSignIn: false
};
}
componentWillMount() {
isSignedIn()
.then(res => {
if (res !== null) {
this.setState({
loggedInStatus: true,
checkedSignIn: true
});
} else {
console.log(res);
}
})
.catch(err => console.log(err));
}
render() {
return <LoginNavigation navigation={this.navigation} />;
}
}
const mapStateToProps = state => ({ nav: state.nav });
export default connect(mapStateToProps)(ReduxNavigation);
To navigate to TestComponent you want your routeName to be testComponent, not the drawer stack. You navigate to specific screens, not navigation components.