How can I render different React components based on the output of Amplify.currentAuthenticatedUser()
(or similar equivalent) ?
The following works -
render() {
if (Auth.user) {
return (
<LoggedInContainer pages={this.state.pages} />
);
} else {
return (
<LoginForm loginHandler={this.login} />
);
};
}
but if I refresh the page the session seems to be lost and I have to re- login, ie I think referencing Auth.user
is sub- optimal.
If I try the following -
render() {
Auth.currentAuthenticatedUser().then(user => {
return (
<LoggedInContainer pages={this.state.pages} />
);
}).catch(e => {
return (
<LoginForm loginHandler={this.login} />
);
});
}
then I get Your render method should have return statement react/require-render-return
If I try the following -
getCurrentUser() {
Auth.currentAuthenticatedUser().then(user => {
console.log(user.attributes.email);
return user.attributes.email;
}).catch(e => {
return undefined;
});
}
render() {
if (this.getCurrentUser()) {
return (
<LoggedInContainer pages={this.state.pages} />
);
} else {
return (
<LoginForm loginHandler={this.login} />
);
};
}
then I never get logged in because the output of getCurrentUser
is always undefined
, despite the fact that the console.log()
line in getCurrentUser
prints out the correct email of the user!
Is there no simple way to get the value of the current Amplify logged- in user, and render different React components according to its value ?
I like to use a switch
statement in combination with an enum
when I'm dealing with rendering different components based on state/value. The switch
deals with rendering the correct component and the enum
values are used to give values to the cases of the switch statement.
What happens in this component:
The component uses 2 state values: authStatus
and user
, both set to the default value.
ComponentDidMount()
gets launched after the initial render and getCurrentUser()
is launched here.
In getCurrentUser()
we set the state depending on the outcome of this function. This state will be used for rendering the correct component.
In render()
the switch
statement will be launched and we use our authStatus
state value for rendering the correct component.
Note: You are dealing with an async request, when none of the cases in the switch
are matched it will render the default case which in my case will render null, this is something you would want to avoid and instead atleast render a load icon or give the user some feedback to what is happening. I created another enum
called ProgressStatus
that can help you with this, you would use this enum
the same way in a switch
statement as the one below.
import React, { Component } from 'react';
export enum AuthStatus {
isLoggedIn = "isLoggedIn",
isNotLoggedIn = "isNotLoggedIn",
Uninitialized = "uninitialized"
}
export enum ProgressStatus {
InProgress = "InProgress",
Uninitialized = "Uninitialized",
Done = "Done",
Error = "Error"
}
class AuthenticationShell extends Component {
state = {
authStatus: AuthStatus.Uninitialized,
user: undefined
}
componentDidMount = () => {
// this function will launch when the component is mounted to the dom
this.getCurrentUser()
}
getCurrentUser = () => {
Auth.currentAuthenticatedUser().then(user => {
// if user is authenticated update authStatus & user state here
this.setState({
authStatus: AuthStatus.isLoggedIn,
user: user.attributes.email
})
}).catch(e => {
// if user is not authenticated update authStatus
this.setState({ authStatus: AuthStatus.isNotLoggedIn })
});
}
render() {
const { authStatus } = this.state;
switch (authStatus) {
case AuthStatus.isLoggedIn:
return (
<div>
<LoggedInContainer />
</div>
)
case AuthStatus.isNotLoggedIn:
return (
<div>
<LoginForm />
</div>
)
default: return null;
// when authstatus is Uninitialized or not isLoggedIn and not isNotLoggedIn null will be rendered
// Rendering null while waiting on some async function is not ideal
}
}
}
export default AuthenticationShell;