Why would the error "Cannot access 'Slice' before initialization" occur when adding an asyncThunk to a Redux RTK slice?

huangapple go评论85阅读模式
英文:

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 &#39;tagsSlice&#39; 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 &#39;@reduxjs/toolkit&#39;;
import thunk from &#39;redux-thunk&#39;;
import appTimeSpanSlice from &#39;./slices/appTimeSpanSlice&#39;;
import authenticationSlice from &#39;./slices/authenticationSlice&#39;;
import uiBehaviorHandlerSlice from &#39;./slices/uiBehaviorHandlerSlice&#39;;
import intervalMiddleware from &#39;./middlewares/intervalMiddleware&#39;;
import pollingMiddleware from &#39;./middlewares/pollingMiddleware&#39;;
import tagsSlice from &#39;./slices/tagsSlice&#39;


export const store = configureStore({
  reducer: {
    tag: tagsSlice, // &lt;--- ERROR IS THROWN HERE
    appTime: appTimeSpanSlice,
    authentication: authenticationSlice,
    ui: uiBehaviorHandlerSlice,
  },
  middleware: [thunk, intervalMiddleware, pollingMiddleware],
});

export type RootState = ReturnType&lt;typeof store.getState&gt;
export type AppThunk&lt;ReturnType = void&gt; = ThunkAction&lt;
  ReturnType,
  RootState,
  unknown,
  Action&lt;string&gt;
&gt;;

Here's my slice :

import { createAsyncThunk, createSlice } from &#39;@reduxjs/toolkit&#39;
import { tagApi } from &#39;services/tag/tagApi&#39;



 export const createTag = createAsyncThunk(
   &#39;tags/createTags&#39;,
   async (body, thunkAPI) =&gt; {
     const response = await tagApi.createTag(body);
     return response.data;
   }
 );

enum Status {
  IDLE = &#39;idle&#39;,
  PENDING = &quot;pending&quot;,
  FULFILLED = &quot;fulfilled&quot;,
  REJECTED = &quot;rejected&quot;
}

interface TagsState {
  tags: [];
  fetchTagsStatus: Status;
  createTagStatus: Status;
}

const initialState = {
  tags: [],
  fetchTagsStatus: Status.IDLE,
  createTagStatus: Status.IDLE
} as TagsState


const tagsSlice = createSlice({
  name: &#39;tags&#39;,
  initialState,
  reducers: {
   testAction: () =&gt; { console.log(&quot;Hello&quot;)}
  },
  extraReducers: (builder) =&gt; {
    builder
     .addCase(createTag.pending, state =&gt; {
       state.createTagStatus = Status.PENDING;
     })
     .addCase(createTag.fulfilled, (state, { payload }) =&gt; {
       state.createTagStatus = Status.FULFILLED;
     })
     .addCase(createTag.rejected, (state, { error }) =&gt; {
       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 &#39;services/api&#39;;
import { selectStart, selectEnd } from &#39;store/slices/appTimeSpanSlice&#39;;
import { store } from &#39;store/store&#39;;

export const tagApi = {
  fetchAllTags: async () =&gt; {
    const start = selectStart(store.getState()); &lt;&lt;&lt; not allowed
    const end = selectEnd(store.getState()); &lt;&lt;&lt; not allowed
    const url = `/api/tags?start=${start}&amp;end=${end}`;
    return await api.get(url);
  },
  createTag: async (body: any) =&gt; {
    const url = `/api/tags`;
    return await api.post(url, body);
  }
};

Here's how I fixed it:

import api from &#39;services/api&#39;;
import { selectStart, selectEnd } from &#39;store/slices/appTimeSpanSlice&#39;;


export const tagApi = {
  fetchAllTags: async (start, end) =&gt; {
    const url = `/api/tags?start=${start}&amp;end=${end}`;
    return await api.get(url);
  },
  createTag: async (body: any) =&gt; {
    const url = `/api/tags`;
    return await api.post(url, body);
  }
};

huangapple
  • 本文由 发表于 2023年6月15日 01:47:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76476289.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定