英文:
Why would the error "Cannot access 'Slice' before initialization" occur when adding an asyncThunk to a Redux RTK slice?
问题
我遇到了一个错误,我很难定位错误的来源。
这个 Web 应用程序是使用 ReactJs / Vite 和 RTK 构建的。
我创建了一个简单的 RTK 切片。
当我在切片中添加一个 asyncThunk 时,应用程序崩溃,并且我收到以下错误消息:
Uncaught ReferenceError: Cannot access 'tagsSlice' before initialization
我已经尝试了一千次。
添加常规的 action reducers 是可以的。
我无法理解为什么会出现这个问题。
与我之前的项目相比,唯一不同的是 Vite。
错误是从 store.ts 抛出的,以下是文件内容:
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
import appTimeSpanSlice from './slices/appTimeSpanSlice';
import authenticationSlice from './slices/authenticationSlice';
import uiBehaviorHandlerSlice from './slices/uiBehaviorHandlerSlice';
import intervalMiddleware from './middlewares/intervalMiddleware';
import pollingMiddleware from './middlewares/pollingMiddleware';
import tagsSlice from './slices/tagsSlice';
export const store = configureStore({
reducer: {
tag: tagsSlice, // <--- ERROR IS THROWN HERE
appTime: appTimeSpanSlice,
authentication: authenticationSlice,
ui: uiBehaviorHandlerSlice,
},
middleware: [thunk, intervalMiddleware, pollingMiddleware],
});
export type RootState = ReturnType<typeof store.getState>
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
以下是我的切片:
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { tagApi } from 'services/tag/tagApi';
export const createTag = createAsyncThunk(
'tags/createTags',
async (body, thunkAPI) => {
const response = await tagApi.createTag(body);
return response.data;
}
);
enum Status {
IDLE = 'idle',
PENDING = "pending",
FULFILLED = "fulfilled",
REJECTED = "rejected"
}
interface TagsState {
tags: [];
fetchTagsStatus: Status;
createTagStatus: Status;
}
const initialState = {
tags: [],
fetchTagsStatus: Status.IDLE,
createTagStatus: Status.IDLE
} as TagsState
const tagsSlice = createSlice({
name: 'tags',
initialState,
reducers: {
testAction: () => { console.log("Hello")}
},
extraReducers: (builder) => {
builder
.addCase(createTag.pending, state => {
state.createTagStatus = Status.PENDING;
})
.addCase(createTag.fulfilled, (state, { payload }) => {
state.createTagStatus = Status.FULFILLED;
})
.addCase(createTag.rejected, (state, { error }) => {
state.createTagStatus = Status.REJECTED;
})
},
})
const { actions, reducer } = tagsSlice;
export const { testAction } = actions;
export default reducer;
总结一下,要重现这个问题,需要满足以下两个条件:
- 切片应包含一个 asyncThunk
- 一个组件应导入该 asyncThunk
故障排除步骤:
- 如果切片中没有 asyncThunk,但导入了
testAction
动作:没有错误 - 如果切片中有 asyncThunk,但组件在文件中没有导入任何内容:没有错误
- 如果切片中有 asyncThunk,只有导入了
testAction
动作:错误
可能导致这种行为的原因是什么?
英文:
I encounter an error which I had hard times to isolate the source.
the web app is built in ReactJs / Vite and RTK.
I created a simple RTK slice.
When I add an asyncThunk to my slice the app crash and I get the following error:
Uncaught ReferenceError: Cannot access 'tagsSlice' before initialization
I've done that one thousand times.
Adding a regular action reducers is fine.
I'm not able to understand why.
The only thing new compared to my previous project is Vite.
The error is thrown from the store.ts, here's the file :
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
import appTimeSpanSlice from './slices/appTimeSpanSlice';
import authenticationSlice from './slices/authenticationSlice';
import uiBehaviorHandlerSlice from './slices/uiBehaviorHandlerSlice';
import intervalMiddleware from './middlewares/intervalMiddleware';
import pollingMiddleware from './middlewares/pollingMiddleware';
import tagsSlice from './slices/tagsSlice'
export const store = configureStore({
reducer: {
tag: tagsSlice, // <--- ERROR IS THROWN HERE
appTime: appTimeSpanSlice,
authentication: authenticationSlice,
ui: uiBehaviorHandlerSlice,
},
middleware: [thunk, intervalMiddleware, pollingMiddleware],
});
export type RootState = ReturnType<typeof store.getState>
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
Here's my slice :
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { tagApi } from 'services/tag/tagApi'
export const createTag = createAsyncThunk(
'tags/createTags',
async (body, thunkAPI) => {
const response = await tagApi.createTag(body);
return response.data;
}
);
enum Status {
IDLE = 'idle',
PENDING = "pending",
FULFILLED = "fulfilled",
REJECTED = "rejected"
}
interface TagsState {
tags: [];
fetchTagsStatus: Status;
createTagStatus: Status;
}
const initialState = {
tags: [],
fetchTagsStatus: Status.IDLE,
createTagStatus: Status.IDLE
} as TagsState
const tagsSlice = createSlice({
name: 'tags',
initialState,
reducers: {
testAction: () => { console.log("Hello")}
},
extraReducers: (builder) => {
builder
.addCase(createTag.pending, state => {
state.createTagStatus = Status.PENDING;
})
.addCase(createTag.fulfilled, (state, { payload }) => {
state.createTagStatus = Status.FULFILLED;
})
.addCase(createTag.rejected, (state, { error }) => {
state.createTagStatus = Status.REJECTED;
})
},
})
const { actions, reducer } = tagsSlice;
export const { testAction } = actions;
export default reducer;
To sum up,
in order to reproduce the issue, 2 conditions should be met:
- the slice should contain an asyncThunk
- a component should import the asyncThunk
TROUBLESHOOTING STEPS:
- If there is NO asyncThunk in the slice but the
testAction
action is imported: no error - If there is an asyncThunk in the slice but the component does not import anything in the file : no error
- If there is an asyncThunk in the slice and only the
testAction
action is imported: error
What would potentially cause this behavior ?
答案1
得分: 0
这是修复后的代码:
import api from 'services/api';
import { selectStart, selectEnd } from 'store/slices/appTimeSpanSlice';
export const tagApi = {
fetchAllTags: async (start, end) => {
const url = `/api/tags?start=${start}&end=${end}`;
return await api.get(url);
},
createTag: async (body) => {
const url = `/api/tags`;
return await api.post(url, body);
}
};
希望这有帮助!如果有任何其他需要,请随时告诉我。
英文:
The issue was that I was trying to access the store outside a React component.
Here's what I had:
import api from 'services/api';
import { selectStart, selectEnd } from 'store/slices/appTimeSpanSlice';
import { store } from 'store/store';
export const tagApi = {
fetchAllTags: async () => {
const start = selectStart(store.getState()); <<< not allowed
const end = selectEnd(store.getState()); <<< not allowed
const url = `/api/tags?start=${start}&end=${end}`;
return await api.get(url);
},
createTag: async (body: any) => {
const url = `/api/tags`;
return await api.post(url, body);
}
};
Here's how I fixed it:
import api from 'services/api';
import { selectStart, selectEnd } from 'store/slices/appTimeSpanSlice';
export const tagApi = {
fetchAllTags: async (start, end) => {
const url = `/api/tags?start=${start}&end=${end}`;
return await api.get(url);
},
createTag: async (body: any) => {
const url = `/api/tags`;
return await api.post(url, body);
}
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论