如何解决saga不监听自定义中间件发出的操作
用例是我需要检查令牌是否已过期。如果令牌已过期,那么我需要调用api以获取新的访问令牌。访问令牌每30分钟失效一次。为此,我试图做的是。
- 在store.js上编写一个名为
checkTokenExpirationMiddleware
的自定义中间件 - 调度
checkToken
操作,以便传奇可以捕获该操作并触发api调用以获取新的访问令牌。 - 在app.js上注入reducer和saga
问题是佐贺听不到那个动作。
这是我所做的代码
store / index.js
import { configureStore,getDefaultMiddleware } from "@reduxjs/toolkit";
import { createInjectorsEnhancer,forceReducerReload } from "redux-injectors";
import createSagaMiddleware from "redux-saga";
const checkTokenExpirationMiddleware = (store) => (next) => (action) => {
console.log("#####action#####",action);
const token = JSON.parse(localStorage.getItem("token"));
if (token && jwt_decode(token).exp < Date.now() / 1000) {
// dispatch checkToken action so that saga will listen this action
// and call api for another access token
const result = next(actions.checkToken());
return result;
// store.dispatch(actions.checkToken());
}
next(action);
};
export function configureAppStore() {
const reduxSagaMonitorOptions = {};
const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);
const { run: runSaga } = sagaMiddleware;
// // Create the store with saga middleware
const middlewares = [sagaMiddleware,checkTokenExpirationMiddleware];
const enhancers = [
createInjectorsEnhancer({
createReducer,runSaga,}),];
const store = configureStore({
reducer: createReducer(),middleware: [...getDefaultMiddleware(),...middlewares],devTools:
/* istanbul ignore next line */
process.env.NODE_ENV !== "production" ||
process.env.PUBLIC_URL.length > 0,enhancers,});
// Make reducers hot reloadable,see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept("./reducers",() => {
forceReducerReload(store);
});
}
return store;
}
store / globalSaga.js
export function* checkToken() {
console.log("checkToken sagaå");
debugger;
// need to call api to get new access token
}
export function* globalSaga() {
// watches for
console.log("global saga watcher");
yield all([
takeLatest(actions.logout,logout),takeEvery(actions.checkToken,checkToken),]);
}
App.js
function App() {
// const dispatch = useDispatch();
console.log("injecting saga and reducer");
useInjectReducer({ key: sliceKey,reducer });
useInjectSaga({ key: sliceKey,saga: globalSaga });
// React.useEffect(() => {
// this executes saga
// console.log("dispatching");
// dispatch(actions.checkToken());
// },[]);
return (
<React.Suspense fallback={<LoadingSpinner />}>
<Router>
<RouterApp />
</Router>
</React.Suspense>
);
}
为什么从中间件分派了checkToken
动作后,传奇故事却无法捕捉到它?
注意:我正在使用reduxjs / toolkit。
更新
我从这里获取了api以获取新的访问令牌。现在我可以获得访问令牌,并且没有无限循环。但是有一个问题,它不会执行以前由于无效令牌(过期)而失败的api。获取新的访问令牌后,现在如何再次执行该api?
const checkTokenExpirationMiddleware = ({ dispatch,getState }) => (
next
) => async (action) => {
const isAlreadyFetchingAccessToken = getState()?.global
.isAlreadyFetchingAccessToken;
const user = JSON.parse(localStorage.getItem("userInfo"));
const access_token = JSON.parse(localStorage.getItem("access_token"));
if (
!isAlreadyFetchingAccessToken &&
access_token &&
jwt_decode(access_token).exp < Date.now() / 1000
) {
const payload = {
data: {
refresh_token: access_token,},};
const response = await request(
"https://localhost:3000/token/refresh",payload,"POST"
);
console.log("#########response#########",response);
if (response?.status === 200) {
localStorage.setItem("token",JSON.stringify(response?.access_token));
dispatch(actions.checkTokenSuccess());
next(action); // now need to call the api with new access token which could not execute due to invalid token(expired)
console.log("action dispatching",action);
}
}
next(action);
};
解决方法
这是因为中间件形成了管道,并且the storeAPI.dispatch
and next
functions do different things
-
storeAPI.dispatch(action)
将操作发送到中间件链的 start ,因此它将遍历所有中间件(包括该中间件)next(action)
将操作发送到链中的 next 中间件。
因此,如果将内容设置为applyMiddleware(sagaMiddleware,myCustomMiddleware)
,并且自定义中间件调用next(action)
,则操作将直接转到化简器,而传奇的中间件将永远不会看到它。
如果您调用storeAPI.dispatch(action)
,它将转到中间件管道的开始,即sagaMiddleware
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。