即使依赖项没有一直改变,useEffect 钩子也会变成无限循环

时间:2021-06-27 16:03:36

标签: javascript reactjs react-hooks

下面是我在 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;

它使用户登录。如您所见,我正在使用钩子。当我从 console.log 钩子登录 useSelector 时,它控制台是更新的状态。然后调用 useEffect 钩子。但问题是登录名并未一直更新。但是 useEffect 仍然进入循环。我错过了什么,我该如何解决?

更新

下面是我的减速机

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

这是操作。

import * as types from './index';

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

2 个答案:

答案 0 :(得分:1)

一个可能的解决方案是解构对象以使比较更容易

  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.

答案 1 :(得分:0)

 if (login && !isSuccess) { // Here
      setSuccess(login.success);
      setMessage(login.message);

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

尝试添加这个,看看是否有效


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;
<块引用>

我将 @reduxjs/toolkit 用于 redux。

如果用户成功登录,您可以声明并更新 isUserLogged 或其他内容的状态。然后,您可以使用 useSelector 在组件内部使用它。

如何使用

const { isUserLogged } = useSelector(state => state.auth)