1

I'm a backend dev, and not too familiar with frontend development, just making some front for solo project... So I'm trying to login user right after setting password. Here's my code:

This is from UserSlice.ts

interface UserSliceState {
    loggedIn: User | undefined;
    fromRegister: boolean;
    error: boolean;
}

interface LoginBody {
    username: string;
    password: string;
}

const initialState: UserSliceState = {
    loggedIn: undefined,
    fromRegister: false,
    error: false
};

export const loginUser = createAsyncThunk(
    'user/login',
    async (body:LoginBody, thunkAPI) => {
        try {
            const req = await axios.post('http://localhost:8000/auth/login', body);
            return req.data;
        } catch(e) {
            thunkAPI.rejectWithValue(e);
        }
    }
)

export const UserSlice = createSlice({
    name: 'user',
    initialState,
    reducers: {
        setFromRegister(state, action:PayloadAction<boolean>) {
            state = {
                ...state,
                fromRegister: action.payload
            }

            return state;
        }
    },
    extraReducers: (builder) => {
        builder.addCase(loginUser.fulfilled, (state, action) => {
            state = {
                ...state,
                loggedIn: {
                    userId: action.payload.user.userId,
                    firstName: action.payload.user.firstName,
                    //... and other properties...
                }
            };

            return state;
        });
    }
});

export const { setFromRegister } = UserSlice.actions;

export default UserSlice.reducer;

This is from last registration form where user supposed to set his password, then UserSlice logins User, and redirects to home page:

useEffect(() => {
    if (state.user.loggedIn) {
        navigate("/home");
    }
    if (state.user.fromRegister) {
        dispatch(loginUser({
            username: state.register.username,
            password: state.register.password
        }));
        return;
    }
    if (state.register.login) {
        dispatch(setFromRegister(true));
    }
}, [state.register.login, state.user.loggedIn, state.user.fromRegister]);

I checked database, password stores as it should.

Redux DevTools says that register state is ok, but user state only changes 'fromRegister' to true and that's all.

In Postman user data returns back like this after login:

{
    "applicationUser": {
        "userId": 2,
        "firstName": "Test",
        "lastName": "User",
        "email": "[email protected]",
        "phone": "1234567890",
        "dateOfBirth": "1990-09-15",
        "username": "testuser767714992",
        "bio": null,
        "nickname": null,
        "profilePicture": null,
        "bannerPicture": null,
        "authorities": [
            {
                "roleId": 1,
                "authority": "USER"
            }
        ],
        "verified": true
    },
    "token": "*long token value*"

Error is ERROR Cannot read properties of undefined (reading 'userId')

But if I change the order of properties, for example, put firstName first, then it replaces it with reading 'firstName'). I can't see where my mistake is.

Tried google it, but have not found any related issue. Some say that there might be a typo, but I checked bunch of times. I expected that after setting password it will automatically login and redirect to home page.

1
  • In case you missed it, or just haven't taken the full tour yet (you earn a badge, BTW), there are 100% completely optional actions one can take after someone answers that helps rate and curate content on the site.
    – Drew Reese
    Commented Dec 8, 2023 at 5:14

1 Answer 1

1

Given response value, e.g. req.data:

{
  "applicationUser": {
    "userId": 2,
    "firstName": "Test",
    "lastName": "User",
    "email": "[email protected]",
    "phone": "1234567890",
    "dateOfBirth": "1990-09-15",
    "username": "testuser767714992",
    "bio": null,
    "nickname": null,
    "profilePicture": null,
    "bannerPicture": null,
    "authorities": [
      {
        "roleId": 1,
        "authority": "USER"
      }
    ],
    "verified": true
  },
  "token": "*long token value*"
}

The reducer is accessing some user property that doesn't exist in the response object, i.e. action.payload.user is undefined. Update the reducer logic to access into action.payload.applicationUser property.

There's also an issue in the reducers. Redux-Toolkit slice reducers should either mutate the current state object or return the next state value, and never reassign the state a new value.

export const UserSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    setFromRegister(state, action:PayloadAction<boolean>) {
      // Mutate state directly
      state.fromRegister = action.payload;
      
      // Or return new state object reference
      // return {
      //   ...state,
      //   fromRegister: action.payload
      // };
    },
  extraReducers: (builder) => {
    builder
      .addCase(loginUser.fulfilled, (state, action) => {
        state.loggedIn = {
          userId: action.payload.applicationUser.userId,
          firstName: action.payload.applicationUser.firstName,
          // ... and other properties...
        };
        // or state.loggedIn = action.payload.applicationUser;
      });
  },
});
1
  • 2
    oh, thank you! appreciate your help very much! I forgot the way I named appUser object in the backend. This is a solution! God bless you!
    – yerokha
    Commented Dec 8, 2023 at 4:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.