I have an actionCreators in my /actions/authenticate.js
to seperate the logic of the actions dispatched by redux and the component of react.
Here is my authenticate.js
which is my actionCreators
export function login(email, password) { // Fake authentication function
return async dispatch => {
dispatch(loginRequest()); // dispatch a login request to update the state
try {
if (email.trim() === "[email protected]" && password === "123456") { //If the email and password matches
const session = { token: "abc1234", email: email, username: "test123" } // Create a fake token for authentication
await AsyncStorage.setItem(DATA_SESSION, JSON.stringify(session)) // Stringinfy the session data and store it
setTimeout(() => { // Add a delay for faking a asynchronous request
dispatch(loginSuccess(session)) // Dispatch a successful sign in after 1.5 seconds
return Promise.resolve()
}, 1500)
} else { // Otherwise display an error to the user
setTimeout(() => { // Dispatch an error state
dispatch(loginFailed("Incorrect email or password"))
}, 1500)
}
} catch (err) { // When something goes wrong
console.log(err)
dispatch(loginFailed("Something went wrong"));
return Promise.reject()
}
};
} // login
Then I import that in my someComponent.js
to import that actionCreator and bind it using bindActionCreators.
Something like this below:
import { bindActionCreators } from "redux";
import * as authActions from "../actions/authenticate";
import { connect } from "react-redux";
Then I connect that action to my component which is the Login.js
export default connect(
state => ({ state: state.authenticate }),
dispatch => ({
actions: bindActionCreators(authActions, dispatch)
})
)(Login);
So I can invoke the function in that actionCreator directly in the Login.js
Something like this below:
onPress={() => {
this.props.actions.login(this.state.email, this.state.password)
}}
But what I want to happen is this function will dispatch an redux action and also return a Promise if that is possible?
Something like this:
onPress={() => {
this.props.actions.login(this.state.email, this.state.password)
.then(() => this.props.navigation.navigate('AuthScreen'))
}}
What I want to happen is when I try to sign in. Dispatch those asynchronous redux thunk actions and as well return a promise. If is been resolved or not so I can redirect or navigate to the correct screen.
Appreciate if someone could help. Thanks in advance.
Your first approach was mostly correct. dispatch(thunkAction())
(or in your case this.props.actions.login()
returns whatever thunkAction()
returns, so it does return Promise in case it's async
.
The problem is what that Promise resolves to, which is whatever you return from the async
function. In your case, you don't wait for setTimeout
and just return void
regardless of whether credentials were correct or not.
So, in terms of async functions you'd need something like
export function login(email, password) { // Fake authentication function
return async dispatch => {
dispatch(loginRequest()); // dispatch a login request to update the state
try {
if (email.trim() === "[email protected]" && password === "123456") { //If the email and password matches
const session = { token: "abc1234", email: email, username: "test123" } // Create a fake token for authentication
await AsyncStorage.setItem(DATA_SESSION, JSON.stringify(session)) // Stringinfy the session data and store it
// Add a delay for faking a asynchronous
await new Promise((resolve, reject) => setTimeout(() => resolve(), 1500));
dispatch(loginSuccess(session));
return Promise.resolve(true);
} else { // Otherwise display an error to the user
await new Promise((resolve, reject) => setTimeout(() => resolve(), 1500));
dispatch(loginFailed("Incorrect email or password"))
return Promise.resolve(false);
}
} catch (err) { // When something goes wrong
console.log(err)
dispatch(loginFailed("Something went wrong"));
return Promise.reject()
}
};
} // login
That way, your async function resolves to true
/false
that you can use in your component:
onPress={() => {
this.props.actions.login(this.state.email, this.state.password)
.then((login_succeeded) => this.props.navigation.navigate('AuthScreen'))
}}
You can also return dispatch(loginSuccess(session));
(as long as it's thunk that returns it and not the setTimeout
handler), in which case loginSuccess(session)
is what .then()
will get in your onPress
hook.