Reputation: 32823
Below is my component in reactjs.
import React, { useState, useEffect } from 'react';
import { Link, Redirect } from 'react-router-dom';
import { connect, useDispatch, useSelector } from 'react-redux';
import { loginUserAction } from '../actions/authenticationActions';
import { setCookie } from '../utils/cookies';
const LoginPage = () => {
const [isSuccess, setSuccess] = useState(false);
const [message, setMessage] = useState('');
const dispatch = useDispatch();
const login = useSelector(state => state.login.response);
console.log(login);
useEffect(() => {
if (login !== undefined) {
setSuccess(login.success);
setMessage(login.message);
if (isSuccess) {
setCookie('token', login.token, 1);
}
}
}, [login]);
const onHandleLogin = (event) => {
event.preventDefault();
const email = event.target.email.value;
const password = event.target.password.value;
dispatch(loginUserAction({
email, password,
}));
}
return (
<div>
<h3>Login Page</h3>
{!isSuccess ? <div>{message}</div> : <Redirect to='dashboard' />}
<form onSubmit={onHandleLogin}>
<div>
<label htmlFor="email">Email</label>
<input type="email" name="email" id="email" />
</div>
<div>
<label htmlFor="password">Password</label>
<input type="password" name="password" id="password" />
</div>
<div>
<button>Login</button>
</div>
</form>
Don't have account? <Link to='register'>Register here</Link>
</div>
);
};
export default LoginPage;
It logs user in. As you can see I am using hooks. When I console.log
login from useSelector
hook, it console's the updated state. Then the useEffect
hook gets called. But the problem is the login is not updating all the time. But still useEffect
goes into a loop. What am I missing and how can I fix this?
UPDATE
Below is my reducer
import * as types from '../actions';
export default function(state = [], action) {
const response = action.response;
switch(action.type) {
case types.LOGIN_USER_SUCCESS:
return { ...state, response };
case types.LOGIN_USER_ERROR:
return { ...state, response };
default:
return state;
}
};
Here is the action.
import * as types from './index';
export const loginUserAction = (user) => {
return {
type: types.LOGIN_USER,
user
}
};
Upvotes: 0
Views: 248
Reputation: 811
A possible solution would be to destructure the object to make the comparison easier
const {message = '', success = false, token = ''} = useSelector(state => state.login.response || {}); //should prevent the error, of response is undefined
console.log(message, success);
useEffect(() => {
//there are other condition options like maybe if(message?.length)
if (message) {
setMessage(message);
}
// Can move setSuccess out of the if, to setSuccess even when it is falsy
if (success) { //note that using isSuccess here might not work cause the state might be the old one still
setSuccess(success)
setCookie('token', token, 1);
}
}, [message, success, token]); //having scalar values (string and boolean) will prevent the loop.
Upvotes: 1
Reputation: 166
if (login && !isSuccess) { // Here
setSuccess(login.success);
setMessage(login.message);
if (isSuccess) {
setCookie('token', login.token, 1);
}
}
Try to add this and see if this works
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
loading: false,
error: null,
user: null,
isUserLogged: false,
};
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
userAuthStart(state, action) {
return {
...state,
loading: true,
error: null,
user: null,
isUserLogged: false,
};
},
userAuthSuccess(state, { payload }) {
return { ...state, loading: false, user: payload, isUserLogged: true };
},
userAuthFail(state, { payload }) {
return { ...state, loading: false, error: payload, isUserLogged: false };
},
userLogout(state) {
return {
...state,
loading: false,
error: null,
user: null,
isUserLogged: false,
};
},
},
});
export const {
userAuthStart,
userAuthSuccess,
userAuthFail,
userLogout,
} = authSlice.actions;
export default authSlice.reducer;
I use
@reduxjs/toolkit
for redux.
You can declare and update state of isUserLogged or something to true if user is logged successfully. Then, you can use useSelector to use it inside components.
const { isUserLogged } = useSelector(state => state.auth)
Upvotes: 0