skip to Main Content

I hope you are well, I have a problem using React together with Redux, the problem is this:
The problem

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


  1. The error caused by a cyclic dependency between those 3 files

    store imports segment -> segment imports http -> http imports store

    One way to resolve this is to make the axios initialization a function with the store as a parameter and call it somewhere else instead of inside http

    That way your http is decoupled from store

    Login or Signup to reply.
  2. Separate out your implementation of store and your call for http. It is due to cyclic dependency and it’s not a good practice to keep cyclic dependencies in your app.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search