Home > Mobile >  Why is my login component not redirecting successful login's to the right page?
Why is my login component not redirecting successful login's to the right page?

Time:03-18

For some reason my Login component is not redirecting a successful login to the right page. I am using a Spring boot backend with a React frontend and am pretty sure I can do this with react on the frontend by using history.push('/profile') to allow a successful login to be redirected to the /profile page but for some reason it stays on /login even after successfully logging in. Any ideas what I am doing wrong? Thank you!

Login.jsx:

import React, {useState, useEffect} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import {Link} from 'react-router-dom';
import {Formik, Field, Form, ErrorMessage} from 'formik';
import * as Yup from 'yup';
import {login} from '../../slices/auth';
import {clearMessage} from '../../slices/messages';
const Login = (props) => {
    const [loading, setLoading] = useState(false);
    const {isLoggedIn} = useSelector((state) => state.auth);
    const {message} = useSelector((state) => state.message);
    const dispatch = useDispatch();
    useEffect(() => {
        dispatch(clearMessage());
    }, [dispatch]);
    const initialValues = {
        username: '',
        password: '',
    };
    const validationSchema = Yup.object().shape({
        username: Yup.string().required('Please enter your username'),
        password: Yup.string().required('Please enter your password'),
    });
    const handleLogin = (formValue) => {
        const {username, password} = formValue;
        setLoading(true);
        dispatch(login({username, password}))
            .unwrap()
            .then(() => {
                props.history.push('/profile');
                window.location.reload();
            })
            .catch(() => {
                setLoading(false);
            });
    };
    if (isLoggedIn) {
        return <Link to='/profile' />;
    }
    return (
        <div className='login'>
            <div className='card card-container'>
                <Formik
                    initialValues={initialValues}
                    validationSchema={validationSchema}
                    onSubmit={handleLogin}
                >
                    <Form>
                        <div className='form-group'>
                            <Field
                                name='username'
                                type='text'
                                className='form-control'
                                placeholder='Username'
                            />
                            <ErrorMessage
                                name='username'
                                component='div'
                                className='alert alert-danger'
                            />
                        </div>
                        <div className='form-group'>
                            <Field
                                name='password'
                                type='password'
                                className='form-control'
                                placeholder='Password'
                            />
                            <ErrorMessage
                                name='password'
                                component='div'
                                className='alert alert-danger'
                            />
                        </div>
                        <div className='form-group'>
                            <button
                                type='submit'
                                className='btn btn-primary btn-block'
                                disabled={loading}
                            >
                                {loading && (
                                    <span className='spinner-border spinner-border-sm'></span>
                                )}
                                <span>Login</span>
                            </button>
                        </div>
                    </Form>
                </Formik>
            </div>
            {message && (
                <div className='form-group'>
                    <div className='alert alert-danger' role='alert'>
                        {message}
                    </div>
                </div>
            )}
        </div>
    );
};
export default Login;

auth.js:

// We’re gonna import AuthService to make asynchronous HTTP requests with trigger one or more dispatch in the result.

// – register(): calls the AuthService.register(username, email, password) & dispatch setMessage if successful/failed
// – login(): calls the AuthService.login(username, password) & dispatch setMessage if successful/failed
// – logout(): calls the AuthService.logout().

// setMessage is imported from message slice that we’ve created above.
// We also need to use Redux Toolkit createAsyncThunk which provides a thunk that will take care of the action types and dispatching the right actions based on the returned promise.
//There are 3 async Thunks to be exported:

// register
// login
// logout

import {createSlice, createAsyncThunk} from '@reduxjs/toolkit';
import {setMessage} from './messages';
import AuthService from '../services/auth.service';
const user = JSON.parse(localStorage.getItem('user'));
export const register = createAsyncThunk(
    'auth/register',
    async ({username, email, password}, thunkAPI) => {
        try {
            const response = await AuthService.register(username, email, password);
            thunkAPI.dispatch(setMessage(response.data.message));
            return response.data;
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();
            thunkAPI.dispatch(setMessage(message));
            return thunkAPI.rejectWithValue();
        }
    }
);
export const login = createAsyncThunk(
    'auth/login',
    async ({username, password}, thunkAPI) => {
        try {
            const data = await AuthService.login(username, password);
            return {user: data};
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();
            thunkAPI.dispatch(setMessage(message));
            return thunkAPI.rejectWithValue();
        }
    }
);
export const logout = createAsyncThunk('auth/logout', async () => {
    await AuthService.logout();
});
const initialState = user
    ? {isLoggedIn: true, user}
    : {isLoggedIn: false, user: null};
const authSlice = createSlice({
    name: 'auth',
    initialState,
    extraReducers: {
        [register.fulfilled]: (state, action) => {
            state.isLoggedIn = false;
        },
        [register.rejected]: (state, action) => {
            state.isLoggedIn = false;
        },
        [login.fulfilled]: (state, action) => {
            state.isLoggedIn = true;
            state.user = action.payload.user;
        },
        [login.rejected]: (state, action) => {
            state.isLoggedIn = false;
            state.user = null;
        },
        [logout.fulfilled]: (state, action) => {
            state.isLoggedIn = false;
            state.user = null;
        },
    },
});
const {reducer} = authSlice;
export default reducer;

messages.js:

// This updates message state when message action is dispatched from anywhere in the application. It exports 2 action creators:

// setMessage
// clearMessage

import {createSlice} from '@reduxjs/toolkit';
const initialState = {};
const messageSlice = createSlice({
    name: 'message',
    initialState,
    reducers: {
        setMessage: (state, action) => {
            return {message: action.payload};
        },
        clearMessage: () => {
            return {message: ''};
        },
    },
});
const {reducer, actions} = messageSlice;
export const {setMessage, clearMessage} = actions;
export default reducer;

CodePudding user response:

Remove the window.location.reload(); from the handleLogin function, it is reloading your app and killing the navigation action.

Since it appears you are using react-router-dom v6, there are no route props and there is no history object. Instead, there is a useNavigate hook.

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

...

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

  ...

  const handleLogin = (formValue) => {
    const { username, password } = formValue;
    setLoading(true);
    dispatch(login({ username, password }))
      .unwrap()
      .then(() => {
        navigate('/profile', { replace: true });
      })
      .catch(() => {
        setLoading(false);
      });
  };

  ...
  • Related