useEffect hook is turning into infinite loop even when the dependency is not changing all the time

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);


  useEffect(() => {
    if (login !== undefined) {

      if (isSuccess) {
        setCookie('token', login.token, 1);
  }, [login]);

  const onHandleLogin = (event) => {

    const email =;
    const password =;

      email, password,

  return (
      <h3>Login Page</h3>
      {!isSuccess ? <div>{message}</div> : <Redirect to='dashboard' />}
      <form onSubmit={onHandleLogin}>
          <label htmlFor="email">Email</label>
          <input type="email" name="email" id="email" />
          <label htmlFor="password">Password</label>
          <input type="password" name="password" id="password" />
      Don't have account? <Link to='register'>Register here</Link>

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?


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 };
      return state;

Here is the action.

import * as types from './index';

export const loginUserAction = (user) => {
  return {
    type: types.LOGIN_USER,


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) {

    // 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
        setCookie('token', token, 1);
  }, [message, success, token]); //having scalar values (string and boolean) will prevent the loop.