React类组件转Hooks时dispatch调用then报错及栈溢出问题咨询
报错原因与修复方案
报错1:Property 'then' does not exist on type '(dispatch: any) => Promise'.ts(2339)
- 原因:
useDispatch默认的TypeScript类型定义没有适配异步中间件(比如你用到的redux-thunk)的返回值规则,TS无法识别dispatch异步thunk action后会返回Promise实例,因此判定返回值上不存在then方法。类组件的mapDispatchToProps中传入的dispatch已经经过react-redux的类型适配,所以不会出现该报错。 - 修复方法:
- 先在全局的Redux类型声明文件中定义适配thunk的Dispatch类型:
// 通常写在redux/store.ts或者全局的类型文件中 import { ThunkDispatch } from 'redux-thunk'; import { RootState, AnyAction } from './你的类型定义路径'; export type AppDispatch = ThunkDispatch<RootState, unknown, AnyAction>;- 组件中使用自定义类型的
useDispatch:
如果你不想调整全局类型,也可以临时用类型断言解决:const dispatch = useDispatch<AppDispatch>();(dispatch(getFloorplan(currentSite.identif)) as Promise<void>).then(...)
报错2:Uncaught RangeError: Maximum call stack size exceeded at getFloorplan
- 原因:你自定义的封装函数和从
../redux/actions导入的异步action重名,导致调用时出现无限递归。你写的const getFloorplan = (site) => dispatch(getFloorplan(site))中,函数内部调用的getFloorplan不是你导入的action,而是你刚声明的当前变量,因此会无限调用自身触发栈溢出。
完整修复后的代码
import { useDispatch, useSelector } from 'react-redux'; // 导入的action保持原名,自定义封装函数换名避免冲突 import { getGraph, getFloorplan, changeActiveCamera, } from "../redux/actions"; // 导入你定义的AppDispatch类型 import { AppDispatch } from '../redux/store'; const YourComponent = () => { const dispatch = useDispatch<AppDispatch>(); const currentSite = useSelector((state) => state.selection.currentSite); const currentCamera = useSelector((state) => state.selection.currentCamera); // 别忘了你原来用到的realGraph也要从store中取 const realGraph = useSelector((state) => state.realGraph); // 封装的函数换名避免和导入的action重名,也可以省略封装直接在loadGraph里写dispatch逻辑 const dispatchGetFloorplan = (site) => dispatch(getFloorplan(site)); const dispatchGetGraph = (site) => dispatch(getGraph(site)); const dispatchChangeActiveCamera = (site, id) => dispatch(changeActiveCamera(site, id)); const loadGraph = () => { if (currentSite) { dispatchGetFloorplan(currentSite.identif).then(() => { console.log("Fetched floorplan"); dispatchGetGraph(currentSite.identif).then(() => { console.log("Fetched model", realGraph.model); if (currentCamera) { dispatchChangeActiveCamera( currentSite.identif, currentCamera.identif ); } }); }); } }; // 剩余组件逻辑... }
如果你不需要单独封装dispatch方法,也可以直接在loadGraph中调用dispatch,代码更简洁:
const loadGraph = () => { if (currentSite) { dispatch(getFloorplan(currentSite.identif)).then(() => { console.log("Fetched floorplan"); dispatch(getGraph(currentSite.identif)).then(() => { console.log("Fetched model", realGraph.model); if (currentCamera) { dispatch(changeActiveCamera(currentSite.identif, currentCamera.identif)); } }); }); } };
内容的提问来源于stack exchange,提问作者user10727450
相关产品推荐
相关产品推荐

