reactjs - 使用redux和react显示全局微调器的问题
问题描述
我的 index.jsx 页面中有一个按钮,它调度了一个激活操作
<StickyButton type="button" onClick={() => dispatch(activate(values))}>
<span>{t("share.button.continue")}</span>
</StickyButton>;
这个动作,调度另一个动作调用 isRequesting() 我在我的微调器中使用它来显示微调器,然后调用 authService 中的一个方法来激活用户:
export const activate = (model) => async (dispatch) => {
await dispatch(isRequesting());
authService
.activate(model)
.then(async (result) => {
authService.setSignedUp();
await dispatch(fetchProfile());
await dispatch(isRequested());
history.push(`${routes.sign_up.base}${routes.sign_up.activated}`);
})
.catch((error) => {
dispatch(errorOccurred());
});
};
authService 激活功能是:
function activate(model) {
let request = {
lang: encryptService.aesStaticEncrypt(localeService.getActiveLanguage()),
ver: encryptService.aesStaticEncrypt(config.app_version),
phoneNumber: encryptService.aesStaticEncrypt(utilService.formatMobileWithPrefix(userService.getMobile())),
invoice: encryptService.aesStaticEncrypt(utilService.getRandomDigit()),
value: {
activationCode: encryptService.aesStaticEncrypt(utilService.formatActivationCode(model.activation_code)),
},
};
return api
.post(`${config.apiUrl}/GATEWAY/ACTIVATIONGATEWAY/V1/Activate`, request)
.then(async (result) => {
return Promise.resolve(result);
})
.catch((error) => {
utilService.handleError(error);
return Promise.reject(error);
});
}
和微调组件:
export const FullPageSpinner = () => {
const { isRequesting } = useSelector((state) => state.request);
console.log("FullPageSpinner");
console.log(isRequesting);
return (
<div
css={{
position: "fixed",
width: "100%",
height: "100%",
display: "flex",
justifyContent: "center",
fontSize: "3rem",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "#00000038",
opacity: isRequesting ? 1 : 0,
zIndex: isRequesting ? "9999999" : "-1",
}}
>
<div css={{ alignSelf: "center", color: "#3e3e3e" }}>
<Spinner />
</div>
</div>
);
};
请求减速器代码:
import * as types from "../actionTypes/request";
const initialState = {
isRequesting: false,
isRequested: false,
};
export default function requestReducer(state = initialState, action) {
if (action.type === types.IsRequesting) {
return {
...state,
isRequesting: true,
isRequested: false
};
}
if (action.type === types.IsRequested) {
return {
...state,
isRequesting: false,
isRequested: true
};
}
if (action.type === types.ErrorOccurred) {
return {
...state,
isRequesting: false,
isRequested: true
};
}
return state;
}
根减速器:
import { combineReducers } from "redux";
import profileReducer from "./profile";
import requestReducer from "./request";
import appReducer from "./app";
const rootReducer = combineReducers({
profile: profileReducer,
request: requestReducer,
app: appReducer,
});
export default rootReducer;
并创建商店:
const store = createStore(
reducer,
compose(
applyMiddleware(thunk),
(window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__()) || compose
)
);
请求动作:
import * as request_types from "../actionTypes/request";
export const isRequesting = () => {
console.log("isRequesting");
return {
type: request_types.IsRequesting,
};
};
export const isRequested = (messages) => {
console.log("isRequested");
return {
type: request_types.IsRequested,
payload: messages,
};
};
请求减速器:
const initialState = {
isRequesting: false,
isRequested: false,
};
export default function requestReducer(state = initialState, action) {
if (action.type === types.IsRequesting) {
return {
...state,
isRequesting: true,
isRequested: false
};
}
if (action.type === types.IsRequested) {
toastService.notify(action.payload);
return {
...state,
isRequesting: false,
isRequested: true
};
}
if (action.type === types.ErrorOccurred) {
return {
...state,
isRequesting: false,
isRequested: true
};
}
return state;
}
和 AppComponent 我根据 isRequesting 将 FullPageSpinner 放在其中呈现
const App = () => {
const { ltr } = useSelector((state) => state.language);
return (
<React.Fragment>
<Routing />
<ToastContainer
position="bottom-center"
autoClose={config.toast_auto_close}
transition={Flip}
{...(!ltr && { rtl: true })}
/>
<FullPageSpinner />
</React.Fragment>
);
};
export default App;
问题是当我调度 isRequesting() 时,状态正在改变,但微调器没有出现,它等到 authService.activate 函数的响应,它可能需要一些时间才能返回。我希望微调器在我发送 isRequesting() 后立即显示,而不是等待响应
解决方案
尝试从激活操作创建者中删除不必要的 async/await:
export const activate = (model) => (dispatch) => { // async here is not necessary
dispatch(isRequesting()); // await here is not necessary
authService
.activate(model)
.then(async (result) => {
authService.setSignedUp();
await dispatch(fetchProfile());
dispatch(isRequested()); // await here is not necessary
history.push(`${routes.sign_up.base}${routes.sign_up.activated}`);
})
.catch((error) => {
dispatch(errorOccurred());
});
};
编辑:
我查看了您在沙箱中添加的示例,并且您的实现在 authService.activate()
那里不是异步的。
我在这里提供了修复: https ://stackblitz.com/edit/react-xplsqp?file=services/auth.js
您的原件authService.activate()
可能是阻塞的,也不是异步的。所以检查你的api.post
是否是异步的。我还建议对您的代码进行一些改进(查看我的评论):
//autService.activate
//...
return api
.post(`${config.apiUrl}/GATEWAY/ACTIVATIONGATEWAY/V1/Activate`, request)
.then(async (result) => { // remove async from here
return Promise.resolve(result); // do not use Promise.resolve, just "return result;" is correct
})
.catch((error) => {
utilService.handleError(error);
return Promise.reject(error); // do not use Promise.reject here, if you want to recatch this error in next chain just "throw error;" instead
});
// ...
推荐阅读
- node.js - Heroku 节点 js 部署问题:Web 进程在启动后 60 秒内无法绑定到 $PORT
- reference - 参考循环的实际例子是什么?
- node.js - Firebase Google 登录异常。内部错误:对 API 的请求被阻止
- php - 在这种情况下应该选择哪个选项,self、static 或 this。它有什么不同吗?
- python-3.x - 使用 python 抓取网站代码
- javascript - 如何使整个跨度可点击?
- javascript - 从嵌套在对象中的数组中随机选择元素的逻辑,该对象进一步嵌套在数组中
- javascript - 如何通过物化 css 的自动完成元素的 onselect 触发事件
- git - Git blame 命令获取两个日期之间的列表
- vba - VBA检查列是否包含特定值