Reputation: 49
I'm trying to log users in based on a isLoggedin state from redux store. My Login Component dispatches the fetchLogin action from the userLogin action mapped to props.
const Login = (props) => {
const [userLogin, setUserLogin] = useState({ email: "", password: "" })
const getValue = e => {
e.preventDefault();
setUserLogin({
...userLogin,
[e.target.name]: e.target.value
});
}
const makeRequest = (e) => {
e.preventDefault()
props.userLogin(userLogin)
if (props.isLoggedin === true) {
console.log(Cookie.get('accessToken'))
props.history.push('/dashboard')
}
}
return (
<Fragment>
<Form onSubmit={makeRequest}>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email Address</Form.Label>
<Form.Control
type="email"
name="email"
placeholder="Enter email"
onChange={getValue}
>
</Form.Control>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
name="password"
placeholder="Enter password"
onChange={getValue}
>
</Form.Control>
</Form.Group>
<Button
variant="primary"
type="submit"
>
Login
</Button>
</Form>
</Fragment>
)
}
const mapStateToProps = (state) => ({
isFetching: state.userReducer.isFetching,
isLoggedin: state.userReducer.isLoggedin,
isError: state.userReducer.isError,
errMessage: state.userReducer.errMessage
});
const mapDispatchToProps = dispatch => ({
userLogin: (userLogin) => {
dispatch(fetchLogin(userLogin))
}
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login)
The problem here is when the user clicks login, the redux action I have which takes care of logging the user in from the backend takes time and the store isn't updated fast enough for the userLogin function to confirm that the user is logged in. I understand this has something to do with promises but I'm not sure how to do it exactly.
You can find my actions below, the only action that matters is the fetchLogin which is the one being dispatched from the login component.
export const userLoginRequest = () => {
return {
type: USER_LOGIN_REQUEST,
payload: {
isFetching: true
}
};
}
export const userLoginSuccess = (user) => {
return {
type: USER_LOGIN_SUCCESS,
payload: {
user: {
...user
},
isLoggedin: true,
isFetching: false
}
};
}
export const userLoginFailed = () => {
return {
type: USER_LOGIN_FAILED,
payload: {
isFetching: false,
isError: true
}
};
}
export const fetchLogin = (userLogin) => dispatch => {
dispatch(userLoginRequest())
axios.post('/login', {
email: userLogin.email,
password: userLogin.password
})
.then(response => {
if (response.status === 200) {
dispatch(userLoginSuccess(response.data))
}
}, err => {
console.log("Error", err)
dispatch(userLoginFailed())
})
}
Upvotes: 1
Views: 2585
Reputation: 10873
You can return the promise from your action and set isLoggedin
state after it's resolved:
export const fetchLogin = (userLogin) => dispatch => {
dispatch(userLoginRequest())
return axios.post('/login', {
email: userLogin.email,
password: userLogin.password
})
.then(response => {
if (response.status === 200) {
dispatch(userLoginSuccess(response.data))
}
return response;
}).catch(err => {
console.log("Error", err)
dispatch(userLoginFailed())
})
}
// ...
const makeRequest = (e) => {
e.preventDefault()
props.userLogin(userLogin).then(resp => {
if (props.isLoggedin === true) {
console.log(Cookie.get('accessToken'))
props.history.push('/dashboard')
}
})
}
Also for this to work you need to update mapDispatchToProps
to actually return the dispatch:
const mapDispatchToProps = dispatch => ({
userLogin: (userLogin) => dispatch(fetchLogin(userLogin))
});
One more thing, I just realised that to properly redirect in this case using the promise from dispatch is actually not necessary since it's possible to track the isLoggedin
prop in useEffect
const makeRequest = (e) => {
e.preventDefault()
props.userLogin(userLogin)
}
useEffect(() => {
if (props.isLoggedin === true) {
console.log(Cookie.get('accessToken'))
props.history.push('/dashboard')
}
}, [props.isLoggedin])
Upvotes: 2