我一直在尝试通过Redux-saga使用Redux-toolkit &反应。似乎用令牌拦截saga调用会在无限循环中获得redux-saga ?还是因为我的监视者?
我最近一直在学习如何编程,所以我在所有领域的技能还不是很好,希望你不要介意代码的编写方式,因为我一直在跟随教程。
On handlessubmission from aHeader.tsx到分派
const handleSubmit = (e) => {
e.preventDefault();
dispatch(getCurrentUser());
};
我的<<p> strong> rootSaga.tsx 包括getCurrentUser()的调度import { takeLatest } from "redux-saga/effects";
import {
handleLogInUser,
handleGetCurrentUser,
handleSetCurrentUser,
} from "./handlers/user";
import {
logInUser,
getCurrentUser,
setCurrentUser,
} from "../slices/user/userSlice";
export function* watcherSaga() {
yield takeLatest(logInUser.type, handleLogInUser);
yield takeLatest(getCurrentUser.type, handleGetCurrentUser);
yield takeLatest(setCurrentUser.type, handleSetCurrentUser);
}
查看器调用handleGetCurrentUser位于用户中的传奇。处理程序中的tsx文件文件夹:
import { call, put } from "redux-saga/effects";
import { setCurrentUser } from "../../slices/user/userSlice";
import { requestLogInUser, requestGetCurrentUser } from "../requests/user";
export function* handleLogInUser(action) {
try {
console.log(action + "in handleLogInUser");
yield call(requestLogInUser(action));
} catch (error) {
console.log(error);
}
}
export function* handleGetCurrentUser(action) {
try {
const response = yield call(requestGetCurrentUser);
const userData = response;
yield put(setCurrentUser({ ...userData }));
} catch (error) {
console.log(error);
}
}
然后使用yield调用requestGetCurrentUser它将请求发送给以下用户。文件夹
import axiosInstance from "../../../axios/Axios";
export function requestGetCurrentUser() {
return axiosInstance.request({ method: "get", url: "/user/currentUser/" });
}
返回响应并放入const userData中,我consoleLog()'d处理程序并发现以下内容:
- 它将成功到达处理程序
- 转到yield调用
- 获取数据成功
- 将数据返回给处理程序
- 然后它重新启动整个yield调用?
它也不会为了放置数据而返回到userSlice。
axiosInstance在myaxios.tsx包含拦截器并获取access_token并将其添加到头文件的文件。
import axios from "axios";
const baseURL = "http://127.0.0.1:8000/api/";
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
Authorization: "Bearer " + localStorage.getItem("access_token"),
"Content-Type": "application/json",
accept: "application/json",
},
});
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
const originalRequest = error.config;
if (typeof error.response === "undefined") {
alert(
"A server/network error occurred. " +
"Looks like CORS might be the problem. " +
"Sorry about this - we will get it fixed shortly."
);
return Promise.reject(error);
}
if (
error.response.status === 401 &&
originalRequest.url === baseURL + "token/refresh/"
) {
window.location.href = "/login/";
return Promise.reject(error);
}
if (
error.response.data.code === "token_not_valid" &&
error.response.status === 401 &&
error.response.statusText === "Unauthorized"
) {
const refreshToken = localStorage.getItem("refresh_token");
if (refreshToken) {
const tokenParts = JSON.parse(atob(refreshToken.split(".")[1]));
// exp date in token is expressed in seconds, while now() returns milliseconds:
const now = Math.ceil(Date.now() / 1000);
console.log(tokenParts.exp);
if (tokenParts.exp > now) {
return axiosInstance
.post("/token/refresh/", {
refresh: refreshToken,
})
.then((response) => {
localStorage.setItem("access_token", response.data.access);
localStorage.setItem("refresh_token", response.data.refresh);
axiosInstance.defaults.headers["Authorization"] =
"JWT " + response.data.access;
originalRequest.headers["Authorization"] =
"JWT " + response.data.access;
return axiosInstance(originalRequest);
})
.catch((err) => {
console.log(err);
});
} else {
console.log("Refresh token is expired", tokenParts.exp, now);
window.location.href = "/login/";
}
} else {
console.log("Refresh token not available.");
window.location.href = "/login/";
}
}
// specific error handling done elsewhere
return Promise.reject(error);
}
);
export default axiosInstance;
userSlice.tsx
import { createSlice } from "@reduxjs/toolkit";
const userSlice = createSlice({
name: "user",
initialState: {},
reducers: {
logInUser(state, action) {},
getCurrentUser() {},
setCurrentUser(state, action) {
const userData = action.payload;
console.log(userData + "we are now back in slice");
return { ...state, ...userData };
},
},
});
export const { logInUser, getCurrentUser, setCurrentUser } = userSlice.actions;
export default userSlice.reducer;
我发现,如果我要删除授权令牌,它只触发一次并退出无限循环,因为它抛出了未经授权的错误。
任何建议都将非常感激,谢谢!
很抱歉这么晚才回来,我刚才碰巧修好了,我不太明白为什么。
但我相信解决它的是以下两件事:
更改发送动作的useEffect,并确保处理程序返回useEffect期望更新的数据。
在处理程序中,我将userData
解构为{ userData }
,我认为这意味着从axios请求返回的数据不是整个请求,而是实际返回的数据。
export function* handleGetCurrentUser() {
try {
console.log("in request get user");
const response = yield call(requestGetCurrentUser);
const { data } = response;
yield put(setCurrentUser({ ...data }));
} catch (error) {
console.log(error);
}
}
我忘记在post中添加usereffect了,它创建了这个动作。
App.tsx中的useEffect
将在App第一次渲染时调度调用。但是,由于返回的数据没有更新预期的内容,所以它继续重新呈现。
我不能确切地记得我的useEffect是什么,但目前它是:
my useEffect in App.tsx
const dispatch = useDispatch();
useEffect(() => {
dispatch(getCurrentUser());
}, [dispatch]);
const user = useSelector((state) => state.user);