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

Time:04-21

I'm working simple reactjs login form with redux/toolkit. I wanted to redirect to dashboard page after successful login. It's throwing following error. I'm new to reactjs and please let me know if I missed anything.

Error:

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;

CodePudding user response:

Issue

You are attempting to use the useNavigate hook outside a React component, which is an invalid use. React hooks must be called at the top-level, they cannot be called conditionally, in functions, loops, etc...

Rules of hooks

Solutions

Pass the navigate function to the submitLogin action creator.

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 the returned 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>
  );
}

CodePudding user response:

When you use react hooks , there are some rules you can't bypass them

  1. You have to call useHook() at the root level of your component or
    function
  2. You can't make conditional useHook() call

I think but maybe i am wrong that error occurred in this part of your code

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