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

React | Redux Toolkit登出后状态重置异常问题求助

问题描述

这是一款基于Firebase授权、Firestore存储,使用React与Redux Toolkit开发的简易应用。用户登出时,我通过dispatch(removeData())、dispatch(removeUserData())重置所有状态数据,状态虽被重置,但获取数据的函数会立即重新执行并再次填充状态(此时user已为null);而页面刷新后状态为空,无用户信息。

如何实现登出后状态重置且不再执行数据获取函数?我已尝试多种基于if user !== null的判断方案,但均无效。若需更多信息可补充。

获取数据代码

const memoizedFetchEmails = useMemo(() => {
  async function fetchEmails() {
     ...
  }
  return fetchEmails;
}, [user]);

const memoizedFetchSubs = useMemo(() => {
  async function fetchSubs() {
     ...
  }
  return fetchSubs;
}, [user]);

const memoizedFetchUserData = useMemo(() => {
  async function fetchUserData() {
    ...
  }
  return fetchUserData;
}, [user]);

useEffect(() => {
  if (user !== null) {
    console.log(user?.uid)
    memoizedFetchEmails();
    memoizedFetchSubs();
    memoizedFetchUserData();
  }
}, [user]);

Redux Actions

removeData(state) {
  state.emails = [];
  state.subs = [];
},

removeUserData(state) {
  state.user = null;
  state.noUser = true;
  state.themeDark = false;
  state.userData = null;
},

登出函数

const logout = () => {
    signOut(auth);
    dispatch(setUser(null))
    dispatch(removeData());
    dispatch(removeUserData());
    navigate("/");
};

Firebase Auth监听代码

useEffect(() => {
  const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
    if (currentUser) {
      dispatch(setUser(currentUser));
    } else {
      dispatch(setUser(null));
    }
  });
  return () => {
    unsubscribe();
  };
}, []);

解决方案

核心问题

登出流程中存在重复状态更新+异步请求未中断的问题:

  1. 手动调用dispatch(setUser(null))和removeUserData时,已经将user设为null,但signOut(auth)会触发Firebase的onAuthStateChanged回调,再次执行dispatch(setUser(null)),导致user状态两次更新,触发监听user的useEffect两次。
  2. 即使user变为null,已经发起的异步数据请求可能仍会继续执行,完成后重新填充状态。

具体修复方案

1. 清理冗余的状态更新

removeUserData已经将state.user设为null,同时signOut(auth)的监听回调也会处理user的重置,手动调用dispatch(setUser(null))属于冗余操作,会导致不必要的状态更新。修改登出函数:

const logout = () => {
    signOut(auth);
    dispatch(removeData());
    dispatch(removeUserData());
    navigate("/");
};

2. 给异步请求加取消机制

使用AbortController中断登出后仍在执行的请求,避免其更新状态:

// 修改数据获取的useEffect
useEffect(() => {
  const controller = new AbortController();
  const signal = controller.signal;

  if (user !== null) {
    const fetchAllData = async () => {
      try {
        // 给每个fetch函数传入signal
        await memoizedFetchEmails(signal);
        await memoizedFetchSubs(signal);
        await memoizedFetchUserData(signal);
      } catch (err) {
        if (err.name === 'AbortError') {
          // 忽略取消请求的错误
          return;
        }
        // 处理其他错误
        console.error('数据获取失败:', err);
      }
    };
    fetchAllData();
  }

  // 组件卸载或user变化时取消所有请求
  return () => controller.abort();
}, [user, memoizedFetchEmails, memoizedFetchSubs, memoizedFetchUserData]);

同时更新memoized的fetch函数,支持接收signal参数(以Firestore为例):

const memoizedFetchEmails = useMemo(() => {
  async function fetchEmails(signal) {
    const querySnapshot = await getDocs(collection(db, 'emails'), { signal });
    // 处理数据并dispatch更新状态
    // ...
  }
  return fetchEmails;
}, [user]);

3. 利用noUser状态加强判断

你在removeUserData中设置了state.noUser = true,可以在useEffect中同时判断user和noUser,确保只有正常登录状态才执行数据获取:

// 从Redux中取出noUser状态
const { user, noUser } = useSelector(state => state.yourSliceName);

useEffect(() => {
  // 仅当user存在且非登出状态时执行
  if (user !== null && !noUser) {
    memoizedFetchEmails();
    memoizedFetchSubs();
    memoizedFetchUserData();
  }
}, [user, noUser, memoizedFetchEmails, memoizedFetchSubs, memoizedFetchUserData]);

4. 优化Auth监听逻辑

避免Auth监听触发不必要的状态更新,只有当Firebase返回的用户与Redux中的用户不一致时才dispatch:

const currentUserFromStore = useSelector(state => state.yourSliceName.user);

useEffect(() => {
  const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
    if (currentUser !== currentUserFromStore) {
      dispatch(setUser(currentUser));
    }
  });
  return () => unsubscribe();
}, [currentUserFromStore]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:17:53