使用redux-thunk时useDispatch钩子报错:TypeError: dispatch is not a function
首先咱们先定位错误的核心原因:你在onClick里直接写了dispatch(logout),这会导致组件渲染时就立刻执行dispatch(logout),而不是点击按钮的时候才触发。而且logout是一个thunk函数(结构为() => dispatch => { ... }),你直接把logout传给dispatch的话,相当于让dispatch执行了这个外层函数,返回的内层函数并没有被正确处理,最终导致点击时触发的不是一个可执行的函数,所以抛出了dispatch is not a function的错误。
第一步:修正点击事件的写法
把onClick改成箭头函数包裹的形式,确保只有点击时才会调用dispatch执行登出的thunk:
// 组件内代码修改后 const dispatch = useDispatch(); <a onClick={() => dispatch(logout())} href='#!' >登出</a>
这里的关键是logout()——调用这个函数后,它会返回那个接收dispatch的内层函数,然后Redux-Thunk中间件会正确处理这个函数,最终触发LOGOUT的action,把isAuthenticated改成false。
第二步:解决TypeScript类型提示问题(可选但推荐)
你看到的useDispatch提示是因为默认的useDispatch不知道Redux-Thunk的存在,所以类型推断会有问题。按照提示创建自定义hook就能解决:
- 首先在你的store文件里导出dispatch的类型:
// store.js/ts import { configureStore } from '@reduxjs/toolkit'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; export const store = configureStore({ reducer: rootReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(thunk), }); // 导出正确的dispatch类型 export type AppDispatch = typeof store.dispatch;
- 创建一个自定义hook文件(比如
hooks.js/ts):
import { useDispatch } from 'react-redux'; import type { AppDispatch } from './store'; // 自定义hook,让dispatch支持thunk类型 export const useThunkDispatch = () => useDispatch<AppDispatch>();
- 在组件里使用这个自定义hook替代默认的
useDispatch:
import { useThunkDispatch } from './hooks'; // 组件内 const dispatch = useThunkDispatch(); <a onClick={() => dispatch(logout())} href='#!' >登出</a>
这样就能消除类型提示的警告,同时让dispatch的类型更准确。
为什么之前的异步功能正常?
你提到之前用axios的异步功能正常,大概率是因为当时你在onClick里用了箭头函数包裹,比如onClick={() => dispatch(fetchData())},这种写法会确保只有点击时才执行dispatch,而这次漏掉了箭头函数和logout()的调用,所以才出了问题。
内容的提问来源于stack exchange,提问作者Shahin Bayat

