我遇到一个问题,仅当我尝试在 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]);
据我所知,您的
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);
}
}
);