You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

redux-saga中await generator执行完成后仍获取旧authorizedError值问题

问题根源
  • 你写的await dispatch(xxx)没有实际生效:默认Redux环境下dispatch普通action返回值是action对象本身,不是Promise,await操作不会等待saga的异步逻辑执行完成,你的判断代码会在登录请求发出后立刻执行,此时saga还未更新authorizedError状态。
  • 闭包快照问题:onSignInPress函数由useCallback生成,内部捕获的authorizedError是当前渲染周期的状态值,就算后续Redux状态更新,当前闭包里的authorizedError还是旧值,不会实时刷新。
解决方案

方案1:通过useEffect监听状态变化(最推荐,符合React单向数据流)

把错误判断逻辑从点击回调里移到单独的useEffect中,专门监听authorizedError的变化触发提示,同时记得新增重置错误状态的action避免重复触发提示。

改造后的组件代码:

const authorizedError = useSelector((state: RootState) => state.user.authorizedError);

// 监听错误状态变化,触发提示
useEffect(() => {
  if (authorizedError) {
    setNotificationErrors(['Wrong login or password']);
    showNotification();
    // 触发提示后重置错误状态,需要在userActions里新增resetSignInError action
    dispatch(userActions.resetSignInError());
  }
}, [authorizedError, dispatch, setNotificationErrors, showNotification]);

const onSignInPress = useCallback(() => {
  // 只需要触发登录请求即可,不需要等待和判断
  dispatch(userActions.postLoginUser({username: email, password}));
}, [validate, email, password, dispatch]);

同时需要在你的用户状态对应的reducer里新增resetSignInError的处理逻辑,将authorizedError重置为false即可。

方案2:改造dispatch支持返回Promise(适合需要在回调内直接拿到请求结果的场景)

默认Redux不支持dispatch返回Promise,你可以给登录action挂载resolve/reject回调,在saga执行完成后调用回调返回结果,改造逻辑如下:

// 组件内点击回调改造
const onSignInPress = useCallback(async () => {
  new Promise((resolve, reject) => {
    dispatch(userActions.postLoginUser({
      payload: {username: email, password},
      resolve,
      reject
    }))
  }).then(() => {
    // 登录成功后续逻辑
  }).catch(() => {
    // 登录失败逻辑
    setNotificationErrors(['Wrong login or password']);
    showNotification();
  })
}, [validate, email, password, dispatch]);

对应saga代码改造:

export default function* postLoginUserSaga({
  payload,
  resolve,
  reject
}: PayloadAction<{payload: UserCredentialsPayload, resolve: Function, reject: Function}>) {
  try {
    yield put(setSignInError(false));
    const {
      data: {
        payload: { access_token },
        status,
      },
    } = yield transport.post(URLS.postLoginUserURL, payload);
    if (status !== "Ok") {
      throw new Error(status);
    }
    yield setItemAsync(ACCESS_TOKEN_KEY, access_token);
    yield put(setSignIn(true));
    resolve?.();
  } catch (error) {
    console.error("User login failed", error);
    yield put(setSignInError(true));
    reject?.(error);
  }
}

内容的提问来源于stack exchange,提问作者Igor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 01:54:03