Я создал собственный хук и создал в нем экземпляр axios для получения новых токенов всякий раз, когда истекает срок действия токена доступа. Первоначально при загрузке страницы с токеном все в порядке, но после истечения времени ожидания мой токен не устанавливается, что не так в моем коде .
Это мой файл useAxiosInstance.js.
import axios from "axios";
import { jwtDecode } from "jwt-decode";
import { useDispatch } from "react-redux";
import { authSuccess } from "../redux/auth/authSlice";
let userData = localStorage.getItem("userData")
? JSON.parse(localStorage.getItem("userData"))
: null;
export const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
headers: {
Authorization: userData?.accessToken
? `Bearer ${userData.accessToken}`
: "",
},
});
const useAxiosInstance = () => {
const getTokens = async (data) => {
try {
const res = await axios.post(
`${process.env.REACT_APP_API_URL}refresh`,
data,
{
headers: {
"Content-Type": "application/json",
},
}
);
return res.data;
} catch (err) {
return err;
}
};
axiosInstance.interceptors.request.use(
async (config) => {
const accessTokenExpiryDate = jwtDecode(userData?.accessToken);
console.info(accessTokenExpiryDate,"ex")
if (accessTokenExpiryDate.exp * 1000 < new Date().getTime()) {
const { accessToken, refreshToken } = await getTokens(
JSON.stringify({ token: userData.refreshToken })
);
userData = {
...userData,
accessToken,
refreshToken,
};
localStorage.setItem("userData", JSON.stringify(userData));
config.headers["Authorization"] = "Bearer " + accessToken;
}
return config;
},
(error) => Promise.reject(error)
);
return userData;
};
export default useAxiosInstance;
Это мой файл app.js
import { useDispatch, useSelector } from "react-redux";
import "./app.less";
import Header from "./components/header/Header";
import { BrowserRouter } from "react-router-dom";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { useEffect } from "react";
import { authSuccess } from "./redux/auth/authSlice";
import AppRoute from "./routes/AppRoute";
import useAxiosInstance from "./utilities/useAxiosInstance"
function App() {
const theme = useSelector((state) => state.theme);
const auth = useSelector((state) => state.auth);
const dispatch = useDispatch();
const userData = useAxiosInstance();
useEffect(() => {
dispatch(authSuccess(userData));
}, [userData, dispatch]);
return (
<BrowserRouter>
<div
className = {theme.mode === "dark" ? "dark-mode app" : "light-mode app"}
>
{auth?.data && <Header />}
<ToastContainer />
<AppRoute />
</div>
</BrowserRouter>
);
}
export default App;
Это мой файл фрагмента аутентификации
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
data: null,
};
const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
authSuccess: (state, action) => {
state.data =action.payload
},
authLogout: (state, action) => {
state.data = null;
},
},
});
export const { authSuccess, authLogout } = authSlice.actions;
export default authSlice.reducer;
это мой файл пользовательского фрагмента
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { showToast } from "../../utilities/toast";
import { authLogout } from "../auth/authSlice";
import { axiosInstance } from "../../utilities/useAxiosInstance";
const initialState = {
update: { loading: false, data: null, error: null },
get: { loading: false, data: null, error: null },
delete: { loading: false, data: null, error: null },
};
export const getUser = createAsyncThunk("user/getUser", (payload) => {
const { data, mode } = payload;
return axiosInstance
.get(`/user/${data?._id}`, {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + data.accessToken,
},
})
.then((res) => res.data)
.catch((error) => {
showToast(error.response.data.message, mode, "error");
throw error.response.data.message;
});
});
export const deleteUser = createAsyncThunk("user/deleteUser", (payload) => {
const { auth, navigate, mode, dispatch } = payload;
return axiosInstance
.delete(`/user/${auth._id}`, {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + auth.accessToken,
},
})
.then((res) => {
showToast("Deleted Successfully!", mode, "success");
dispatch(authLogout());
localStorage.removeItem("userData");
navigate("/");
})
.catch((err) => {
showToast(err?.response?.data?.message, mode, "error");
throw err.response.data.message;
});
});
export const editUser = createAsyncThunk("user/editUser", (payload) => {
const { form, data, mode } = payload;
return axiosInstance
.put(`/user/${data._id}`, form, {
headers: {
"Content-Type": "multipart/form-data",
// Authorization: "Bearer " + data.accessToken,
},
})
.then((res) => {
showToast("Updated Successfully!", mode, "success");
})
.catch((err) => {
showToast(err?.response?.data?.message, mode, "error");
throw err.response.data.message;
});
});
const userSlice = createSlice({
name: "user",
initialState,
extraReducers: (builder) => {
builder.addCase(getUser.pending, (state, action) => {
state.get.loading = true;
});
builder.addCase(getUser.fulfilled, (state, action) => {
state.get.loading = false;
state.get.data = action.payload;
});
builder.addCase(getUser.rejected, (state, action) => {
state.get.loading = false;
state.get.error = action.payload;
});
builder.addCase(editUser.pending, (state, action) => {
state.update.loading = true;
});
builder.addCase(editUser.fulfilled, (state, action) => {
state.update.loading = false;
state.update.data = action.payload;
});
builder.addCase(editUser.rejected, (state, action) => {
state.update.loading = false;
state.update.error = action.payload;
});
builder.addCase(deleteUser.pending, (state, action) => {
state.delete.loading = true;
});
builder.addCase(deleteUser.fulfilled, (state, action) => {
state.delete.loading = false;
state.delete.data = action.payload;
});
builder.addCase(deleteUser.rejected, (state, action) => {
state.delete.loading = false;
state.delete.error = action.payload;
});
},
});
export default userSlice.reducer;
поскольку я вызываю getUser api при загрузке страницы, он вызывает пользовательский крючок, но для редактирования и удаления только до тех пор, пока токен доступа не существует, он работает, а в остальное время мой новый токен не обновляется
🤔 А знаете ли вы, что...
JavaScript поддерживает работу с различными форматами данных, такими как JSON и XML.