【问题标题】:Problem showing global spinner using redux and react使用 redux 和 react 显示全局微调器的问题
【发布时间】:2020-06-30 04:39:19
【问题描述】:

我的 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>
  );
};

请求reducer代码:

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() 后立即显示,而不是等待

【问题讨论】:

  • 你为什么要等待发货?你能包括你的动作创建者和reducer代码吗?
  • @DrewReese 我更新了问题。顺便说一句,我删除了等待调度,但问题没有解决。

标签: reactjs redux react-redux spinner


【解决方案1】:

尝试从激活操作创建器中删除不必要的 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是否是异步的。我还建议对您的代码进行一些改进(检查我的 cmets):

//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
    });
// ...

【讨论】:

  • 实际上这个 aciton 中的所有 async/await 都是不必要的,我删除了所有这些,但问题仍然存在。
  • 你能把你的isRequestingisRequested动作创建者的实现也放在这里吗?
  • 是的,我更新了问题并提出了这些实现。
  • 看起来也不错。您能否在渲染FullPageSpinner 以及使用activate 响应的位置添加一个父组件?
  • 我更新了问题并将 FullPageSpinner 的父级放入 AppComponent。顺便说一句,我不使用激活响应,只是根据激活的响应将用户重定向到另一个页面,这可能需要一段时间让服务器响应
猜你喜欢
  • 1970-01-01
  • 2020-04-07
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多