Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Next13 'Cannot access 'slice' before initialization' when using createAsyncThunk

I want to fetch some user data from the backend directly into redux and for that, I used createAsyncThunk. I've created the slice and I made a getUserData function inside the slice file using createAsyncThunkand added theextraReducers`.

The issue is that I need to dispatch the function and I want to dispatch it after I get the token from the backend because I need to send the token back to get the user backend. But if I call the dispatch of getUserData() inside the login function when I run npm run build I get this error

An Error occurred prerendering page "/login". Read more:

https://nextjs.org/docs/messages/prerender-error
ReferenceError: Cannot access 'slice' before initialization

My file structure looks like this:

enter image description here

The store is outside of the src directory.

I tried to dispatch getUserData() in other files. If I dispatch it inside the main page from the app I get this error when I run npm run build.

Collecting page data .ReferenceError: Cannot access 'user_slice' before initialization

I should mention that I do not use this file yet. I have set up in next.config.ts a redirect from '/' to a different page.

If I dispatch it inside the main layout, or any other layouts I get this error directly into the browser.

Error: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization
src\store\createStore.ts (33:11) @ userSlice

  31 | authSlice,
  32 | modalSlice,
> 33 | userSlice,
     |         ^
  34 | currencySlice,
  35 | });
  36 | 

But if I dispatch the function inside the shop page works fine... but, it doesn't make sense to dispatch the function there.

I have even created a codesandbox and I added all the files. I've also deleted a lot of things to manage to make the app work inside the codesandbox and some sensitive code. The funny thing is that inside the codesandbox the build works fine... Here is the codesandbox (If the app doesn't run for you please go to terminal user ctrl + c and the npm run dev).

I have no idea why it works fine inside the shop page but not on the login page and also why it worked inside the codesandbox. Can someone please help?

Store code:

import { combineReducers } from 'redux';
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
import createWebStorage from 'redux-persist/lib/storage/createWebStorage';

import authSlice from './auth/slice';
import modalSlice from './modal/slice';
import userSlice from './user/slice';
import currencySlice from './currency/slice';

const createNoopStorage = () => {
  return {
    getItem(_key: any) {
      return Promise.resolve(null);
    },
    setItem(_key: any, value: any) {
      return Promise.resolve(value);
    },
    removeItem(_key: any) {
      return Promise.resolve();
    },
  };
};

const storage =
  typeof window !== 'undefined'
    ? createWebStorage('local')
    : createNoopStorage();

const rootReducer = combineReducers({
  authSlice,
  modalSlice,
  userSlice,
  currencySlice,
});

const persistConfig = {
  key: 'root',
  storage,
  whitelist: ['authSlice', 'userSlice'],
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
    }),
});

export const persistor = persistStore(store);

export type RootState = ReturnType<typeof rootReducer>;
export type AppDispatch = ReturnType<typeof store.dispatch>;

The Slice code:

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

import { initialState } from './initialsState';
import { get } from '@/helpers/utils/fetch';

export const getUserData = createAsyncThunk('user/userData', async () => {
  try {
    return await get({ url: '/api/user' });
  } catch (error) {
    console.log('thunk user data error: ', error);
  }
});

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    clearUserData: (state) => {
      state.user = null;
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(getUserData.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(getUserData.fulfilled, (state, action) => {
        state.status = 'success';
        state.user = action.payload;
      })
      .addCase(getUserData.rejected, (state, action) => {
        (state.status = 'failed'), (state.error = action.error.message);
      });
  },
});

export const { clearUserData } = userSlice.actions;

export default userSlice.reducer;

The login function

  const onLogin = async () => {
    setIsLoading(true);
    try {
      const response = await axiosInstance.post('/api/auth/login', userData);
      const token = response.data.accessTokens;

      dispatch(setToken(token));
      (dispatch as ThunkDispatch<RootState, void, AnyAction>)(getUserData());

      push(routes.shop);
      setError('');
      setIsLoading(false);
    } catch (error: any) {
      setIsLoading(false);
      if (error.response && error.response.status === 400) {
        setError('Incorrect credentials');
      } else {
        console.log('Login Error', error);
      }
    }
  };
like image 699
Oliver Avatar asked Jun 19 '26 06:06

Oliver


1 Answers

From what I can tell it looks like your getUserData action is trying to close over and use the store prior to the store being instantiated. The file that creates the store object is importing from the file that creates the slice.

Instead of importing the store, the getUserData action should use the second argument that is passed to the payload creator, e.g. the thunkAPI object.

Example:

export const getUserData = createAsyncThunk(
  'user/userData',
  async (_, thunkApi) => {
    try {
      const userToken = userTokenSelector(thunkApi.getState());

      if (userToken) {
        console.log(userToken);
        return await get({ url: '/api/user' });
      }
    } catch (error) {
      console.log('thunk user data error: ', error);
      return thunkApi.rejectWithValue(error);
    }
  }
);
like image 76
Drew Reese Avatar answered Jun 21 '26 23:06

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!