能否从ThunkAction返回unsubscribeSnapshot等取消订阅引用?
问题:能否从Redux Thunk Action返回订阅取消函数的引用?
请问是否可以像以下示例这样,从ThunkAction返回unsubscribeSnapshot的引用?
export const someFetchAction = () => async (dispatch: Dispatch, getState: GetState) => { let unsubscribeAuth: UnsubscribeAuth | null = null; let unsubscribeSnapshot: UnsubscribeSnapshot | null = null; try { // 监听认证状态变化 unsubscribeAuth = getAuth().onAuthStateChanged(user => { // 检查用户是否已认证 }); // 监听快照更新 unsubscribeSnapshot = onSnapshot(queryRef, (docsSnapshot) => { // 分发数据并将loaded设为true }) return { unsubscribe: () => { if (unsubscribeAuth && unsubscribeSnapshot) { unsubscribeAuth(); unsubscribeSnapshot(); } } } catch(error) { // 分发错误并将error标志设为true if (unsubscribeAuth && unsubscribeSnapshot) { unsubscribeAuth(); unsubscribeSnapshot(); } } }
我尝试在React的
useEffect中调用该方法:
const { loaded } = useSelector(state => ({ loaded: state.fireReducer.loaded, })) const { someFetchAction } = useActions({ someFireAction: fireActions.someFireAction, }); useEffect(() => { let actionRef; if (!loaded) { actionRef = someFireAction(); } return () => { actionRef.unsubscribe(); } }, [loaded])
回答:
这种做法是可行的,但需要修正几个关键问题才能正常运行:
- 处理异步Thunk的返回值
你的Thunk是async函数,调用someFireAction()后返回的是一个Promise,而非直接拿到包含unsubscribe的对象。当前代码直接访问actionRef.unsubscribe()会报错,需要改为异步获取返回值:
useEffect(() => { let unsubscribeFn; if (!loaded) { someFireAction().then(result => { unsubscribeFn = result?.unsubscribe; }); } return () => { if (unsubscribeFn) { unsubscribeFn(); } } }, [loaded])
空值安全检查
当loaded初始值为true时,actionRef会是undefined,此时清理函数调用actionRef.unsubscribe()会抛出错误,必须先判断函数是否存在再执行。Thunk内部的订阅完整性
确保onAuthStateChanged和onSnapshot的订阅函数都能被正确赋值,避免出现其中一个订阅成功、另一个失败时,漏取消已成功的订阅(当前代码的try/catch已经处理了这种情况,无需修改)。TypeScript类型优化(可选)
如果使用TypeScript,需要给Thunk的返回值定义明确类型,避免类型报错:
import { ThunkAction, AnyAction } from '@reduxjs/toolkit'; import { RootState } from '../store'; type UnsubscribeFn = () => void; type ThunkReturn = Promise<{ unsubscribe: UnsubscribeFn } | undefined>; export const someFetchAction = (): ThunkAction<ThunkReturn, RootState, unknown, AnyAction> => async (dispatch, getState) => { // 原有逻辑 }
内容的提问来源于stack exchange,提问作者WichyCake
相关产品推荐
相关产品推荐

