Next13 使用 createAsyncThunk 时无法在初始化之前访问“切片”

问题描述 投票:0回答:1

我遇到一个问题,仅当我尝试在 Next13 应用程序上运行

npm run build
时才会出现。 我得到的错误是这个
Error occurred prerendering page "/login". Read more: https://nextjs.org/docs/messages/prerender-error ReferenceError: Cannot access 'slice' before initialization

我将 Next13 与 Redux 和 Redux Persist 一起使用,因为我从后端获取了一个令牌,并将其保存在 Redux 中并使用 Redux Persist 进行持久化。所有其他端点都需要标头中的此令牌才能发送正确的数据。

我的问题是,我试图通过使用

createAsyncThunk
获取一些用户数据来将其保存到 Redux 中。我为用户创建了
slice
和一个函数
getUserData
,在获得
login
后我在
token
函数中调度该函数。

一切正常,我能够在我的应用程序中使用数据。当我尝试运行

npm run build
时出现问题,我收到上面的错误。

最初,我认为问题在于提取发生在我获得令牌之前,所以我试图确保情况并非如此。这就是为什么代码可能有点奇怪。

这是我的代码,如果有人可以提供帮助:

商店

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';

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,
});

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>;

切片

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

    if (userToken) {
      console.log(userToken);
      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;

我在

getUserData

中使用的get函数
export const get = ({ url, customHeaders }: FetchTypes): Promise<any> => {
  const token = store.getState().authSlice.user.token;

  const authHeaders = {
    Authorization: `Bearer ${token}`,
  };

  const headers = {
    ...customHeaders,
    ...authHeaders,
  };

  return new Promise((resolve, reject) => {
    axiosInstance
      .get(url, { headers })
      .then((response) => {
        resolve(response.data);
      })
      .catch((error) => {
        console.log(error);
        if (error?.response?.status === 403) handleNoToken();

        reject(error);
      });
  });
};

登录函数和调度函数

getUserData

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

      dispatch(setToken(token));
      console.log('loggedIn');

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

  const dispatchUserData = async () => {
    if (tokenSelector) {
      await (dispatch as ThunkDispatch<RootState, void, AnyAction>)(
        getUserData()
      );
      console.log('dispatchUserData');
    }
  };

  useEffect(() => {
    dispatchUserData();
  }, [tokenSelector]);

reactjs next.js redux redux-thunk next.js13
1个回答
0
投票

据我所知,您的

getUserData
操作似乎试图在实例化
store
之前关闭并使用
store

而不是导入

store
getUserData
操作应使用传递给 payload Creator 的第二个参数,例如
thunkAPI
对象。

示例:

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);
    }
  }
);
© www.soinside.com 2019 - 2024. All rights reserved.