1

I am creating a NextJs 14 ecommerce application using redux toolkit for state management. I have created a slice using my best understanding of RTK 2.0 syntax to call user data so that it can be added to my user state.

"use client";

import { buildCreateSlice, asyncThunkCreator } from "@reduxjs/toolkit";

const createSliceWithThunks = buildCreateSlice({
  creators: {
    asyncThunk: asyncThunkCreator,
  },
});

const initialState = {
  user: {
    _id: "",
    fname: "",
    lname: "",
    email: "",
    streetAddress: "",
    postalCode: "",
    city: "",
    county: "",
    country: "",
  },
  loading: false,
  error: null,
};

const userSlice = createSliceWithThunks({
  name: "user",
  initialState,
  reducers: (create) => ({
    fetchUser: create.asyncThunk(
      async (_, thunkApi) => {
        const response = await fetch("/api/user");
        if (!response.ok) {
          throw new Error("Failed to fetch user data");
        }
        const userData = await response.json();
        console.log(userData);
        return userData;
      },
      {
        pending: (state) => {
          (state.loading = true), (state.error = null);
        },
        fulfilled: (state, action) => {
          state.loading = false;
          state.data = action.payload;
        },
        rejected: (state, action) => {
          state.loading = false;
          state.error = action.error.message;
        },
      }
    ),
  }),
});

export const { fetchUser } = userSlice.actions;
export default userSlice.reducer;

This is my api/user route:

import { connectDb } from "@dbConfig/db";
import User from "@models/UserModel";
import { getServerSession } from "next-auth";
import { NextResponse } from "next/server";

export async function GET(req, res) {
  const session = getServerSession(); //using my session data from NextAuth to get email to find user in mongodb

  try {
    const email = (await session).user.email; //I don't know why prettier formatted this line like this, the code breaks if I change it.

    connectDb();

    const user = await User.findOne({ email });
    console.log(user);

    return NextResponse.json({ message: "User found:", user }, { status: 201 });
  } catch (error) {
    console.log(error);
  }
}

The call works perfectly, I am getting the user data from my database and can see it when I go to localhost:3000/api/user. The problem is when I try to get it using Redux-Toolkit and then set my user state to the data received. When I check the Redux-Devtools in my browser, I can see the data, but it is only appearing under a data property, and not actually updating state. I am at a loss for how to move forward. Any help is appreciated.

redux dev tool screenshot

1
  • 1
    Someone suggested an edit, but they unfortunately modified the code in the process which would be incorrect for Next.js. I've corrected the edit. You should be able to see, and approve, suggested edits on your own posts though IIRC. Commented Feb 4, 2024 at 1:12

1 Answer 1

1

The state is actually updating, you can see the updated state in the dev tool.

However...

There is no data property in the state until this fetchUser action is fulfilled, in which case the reducer case sets a state.data property equal to action.payload. I suspect you want to be setting the state.user property to the user property of the response JSON in the action payload, e.g. state.user = action.payload.user;.

const initialState = {
  user: {
    _id: "",
    fname: "",
    lname: "",
    email: "",
    streetAddress: "",
    postalCode: "",
    city: "",
    county: "",
    country: "",
  },
  loading: false,
  error: null,
};
const userSlice = createSliceWithThunks({
  name: "user",
  initialState,
  reducers: (create) => ({
    fetchUser: create.asyncThunk(
      async (_, thunkApi) => {
        try {
          const response = await fetch("/api/user");
          const userData = await response.json();
          return userData;
        } catch(error) {
          return thunkApi.rejectWithValue(error);
        }
      },
      {
        pending: (state) => {
          state.loading = true;
          state.error = null;
        },
        fulfilled: (state, action) => {
          state.loading = false;
          state.user = action.payload.user; // <-- update user property
        },
        rejected: (state, action) => {
          state.loading = false;
          state.error = action.payload.message;
        },
      }
    ),
  }),
});
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.