I hope you are well, I have a problem using React together with Redux, the problem is this:
I’m getting a "ReferenceError: Cannot access ‘authSlice’ before initialization". I think the problem is that I have a class called http, and there I import store, and then in my slice class I import an http method, I think that’s it. But it’s because I need to access the store, I attach my store, segment and http class:
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { HOST } from "../http/utils";
import makeApiCall from "../http"; //Possible cause
const accessToken = localStorage.getItem("accessToken");
const refreshToken = localStorage.getItem("refreshToken");
const username = localStorage.getItem("username");
const initialState = {
username: username || null,
password: null,
isLoading: false,
error: null,
accessToken: accessToken || null,
refreshToken: refreshToken || null,
};
export const loginUser = createAsyncThunk(
"api/login",
async (payload, { rejectWithValue }) => {
const url = HOST.concat("api/token/");
return makeApiCall(url, "POST", payload, rejectWithValue);
},
);
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
logout: (state) => {
state.accessToken = null;
state.refreshToken = null;
state.username = null;
state.password = null;
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
},
refresh: (state, action) => {
state.refreshToken = action.payload.refresh;
state.accessToken = action.payload.access;
},
setError: (state, action) => {
state.error = action.payload;
state.isLoading = false;
},
},
extraReducers: (builder) => {
builder
.addCase(loginUser.pending, (state, action) => {
state.isLoading = true;
})
.addCase(loginUser.fulfilled, (state, action) => {
state.accessToken = action.payload.access;
state.refreshToken = action.payload.refresh;
localStorage.setItem("accessToken", state.accessToken);
localStorage.setItem("refreshToken", state.refreshToken);
state.isLoading = false;
})
.addCase(loginUser.rejected, (state, action) => {
state.error = action.payload;
state.isLoading = false;
});
},
});
export const { logout, setError, refresh } = authSlice.actions;
export default authSlice.reducer;
Here my store configuration:
import { configureStore } from "@reduxjs/toolkit";
import { authSlice } from "./authSlice";
import { userSlice } from "./userSlice";
export const store = configureStore({
reducer: {
auth: authSlice.reducer,
user: userSlice.reducer,
},
});
and here my class http:
import axios from "axios";
import { store } from "../redux/store"; //Possible cause
import { HOST } from "./utils";
const getHeaders = () => {
const headers = {
Accept: "application/json",
"Content-type": "Application/json",
};
const access = store.getState().auth.accessToken;
if (access) {
headers.Authorization = `Bearer ${access}`;
}
return headers;
};
const refreshAccessToken = async function () {
return axios
.request({
method: "POST",
url: HOST.concat("/api/v1/auth/refresh/"),
data: {
refresh: store.getState().auth.refreshToken,
},
})
.then((response) => {
if (response.status === 200) {
store.dispatch({
type: "auth/refresh",
payload: response.data,
});
}
})
.catch(() => {
store.dispatch({
type: "auth/logout",
});
});
};
const axiosClient = axios.create();
axiosClient.interceptors.request.use(
async (config) => {
config.headers = getHeaders();
return config;
},
(error) => {
return Promise.reject(error);
},
);
axiosClient.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
let response_status;
try {
response_status = error.response.status;
} catch (e) {
response_status = 200;
}
const originalRequest = error.config;
if (response_status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
await refreshAccessToken();
return axiosClient(originalRequest);
}
return Promise.reject(error);
},
);
export default async function makeApiCall(url, method, data, rejectWithValue) {
return new Promise((resolve, reject) => {
axiosClient
.request({
url,
method,
data,
})
.then((response) => {
resolve(response.data);
})
.catch((error) => {
reject(rejectWithValue(error.response.data));
});
});
}
I hope you can help me, if you need me to show you something else just ask, thank you very much in advance for reading my problem, I hope you can help me.
I hope you can help me solve a problem, I use React and Redux, but I am getting a:
ReferenceError: Cannot access ‘authSlice’ before initialization
2
Answers
The error caused by a cyclic dependency between those 3 files
store
importssegment
->segment
importshttp
->http
importsstore
One way to resolve this is to make the
axios
initialization a function with thestore
as a parameter and call it somewhere else instead of insidehttp
That way your
http
is decoupled fromstore
Separate out your implementation of
store
and your call forhttp
. It is due to cyclic dependency and it’s not a good practice to keep cyclic dependencies in your app.