使用 react-router-dom (v6) 成功登录后,Reactjs 重定向到仪表板页面

Reactjs redirect to dashboard page after successful login with react-router-dom (v6)

我正在使用 redux/toolkit 处理简单的 reactjs 登录表单。我想在成功登录后重定向到 dashboard 页面。它抛出以下错误。我是 reactjs 的新手,如果我遗漏了什么请告诉我。

错误:

Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

authSlice.js

import { useNavigate } from 'react-router-dom';


export const submitLogin =
  ({
    email,
    password
  }) =>
  async dispatch => {
    const history = useNavigate();

    return jwtService
      .signInWithEmailAndPassword(email, password)
      .then(user => {
        history('/dashboard');
        return dispatch(loginSuccess());
      })
      .catch(error => {
        return dispatch(loginError(error));
      });
  };


const authSlice = createSlice({
    name: 'auth',
    initialState,
    reducers: {
        loginSuccess: ....
        loginError: ....
        logoutSuccess: ....
    },
    extraReducers: {},
});

export const { loginSuccess, loginError, logoutSuccess } = authSlice.actions;

export default authSlice.reducer;

Login.js

const Login = () => {
   function handleSubmit(model) {
     dispatch(submitLogin(model));
   }

   return (
       <Formsy onValidSubmit={handleSubmit} ref={formRef}>
           <input type="text" placeholder="username" />
           ....
       </Formsy>
    )
}

App.js

<Routes>
  <Route path="/dashboard" element={<ProtectedRoutes />}>
  <Route path="" element={<Dashboard />} />
  </Route>
  <Route exact path="/" element={<Login />} />
  <Route path="*" element={<PageNotFound />} />
</Routes>
import React from 'react';
import { useSelector } from 'react-redux';
import { Navigate, Outlet } from 'react-router-dom';

const useAuth = () => {
    const auth = useSelector(({ auth }) => auth);
    return auth && auth.loggedIn;
};

const ProtectedRoutes = () => {
    const isAuth = useAuth();
    return isAuth ? <Outlet /> : <Navigate to="/" />
}

export default ProtectedRoutes;

当你使用 react hooks 时,有一些规则你不能绕过它们

  1. 您必须在组件的根级别调用 useHook() 或
    函数
  2. 您不能进行有条件的 useHook() 调用

我想,但也许我错了,你的这部分代码出现了错误

export const submitLogin =
  ({
    email,
    password
  }) =>
  async dispatch => {
    const history = useNavigate(); // x Wrong you can't call inside another function
    ...
  };

问题

您正试图在 React 组件之外使用 useNavigate 挂钩,这是一种无效的使用。 React hooks 必须在 top-level 处调用,它们不能有条件地在函数、循环等中调用...

Rules of hooks

解决方案

将导航功能传递给 submitLogin 动作创建者。

export const submitLogin = ({ email, password }, navigate) =>
  async dispatch => {
    return jwtService
      .signInWithEmailAndPassword(email, password)
      .then(user => {
        navigate('/dashboard');
        return dispatch(loginSuccess());
      })
      .catch(error => {
        return dispatch(loginError(error));
      });
  };

...

const Login = () => {
  const navigate = useNavigate();

  function handleSubmit(model) {
    dispatch(submitLogin(model, navigate));
  }

  return (
    <Formsy onValidSubmit={handleSubmit} ref={formRef}>
      <input type="text" placeholder="username" />
      ....
    </Formsy>
  );
}

Chain/await 返回的 Promise

export const submitLogin = ({ email, password }) =>
  async dispatch => {
    return jwtService
      .signInWithEmailAndPassword(email, password)
      .then(user => {
        dispatch(loginSuccess());
        return user;
      })
      .catch(error => {
        dispatch(loginError(error));
        throw error;
      });
  };

...

const Login = () => {
  const navigate = useNavigate();

  async function handleSubmit(model) {
    try {
      await dispatch(submitLogin(model));
      navigate('/dashboard');
    } catch(error) {
      // handle error, log, etc...
    }
  }

  return (
    <Formsy onValidSubmit={handleSubmit} ref={formRef}>
      <input type="text" placeholder="username" />
      ....
    </Formsy>
  );
}