React Native使用Redux调用API时出现Invalid Hook Call错误
React Native + Redux 无效Hook调用错误排查与修复
错误信息
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem. This error is located at: in ComplaintsMenu (created by HomePage) in RCTView (created by View) in View (created by HomePage) in RCTView (created by View) in View (created by HomePage) in HomePage (created by SceneView) in StaticContainer in EnsureSingleNavigator (created by SceneView) in SceneView (created by CardContainer) in RCTView (created by View) in View (created by CardContainer) in RCTView (created by View) in View (created by CardContainer) in RCTView (created by View) in View in CardSheet (created by Card) in RCTView (created by View) in View (created by AnimatedComponent) in AnimatedComponent in AnimatedComponentWrapper (created by PanGestureHandler) in PanGestureHandler (created by PanGestureHandler) in PanGestureHandler (created by Card) in RCTView (created by View) in View (created by AnimatedComponent) in AnimatedComponent in AnimatedComponentWrapper (created by Card) in RCTView (created by View) in View (created by Card) in Card (created by CardContainer) in CardContainer (created by CardStack) in RNSScreen (created by AnimatedComponent) in AnimatedComponent in AnimatedComponentWrapper (created by InnerScreen) in Suspender (created by Freeze) in Suspense (created by Freeze) in Freeze (created by DelayedFreeze) in DelayedFreeze (created by InnerScreen) in InnerScreen (created by Screen) in Screen (created by MaybeScreen) in MaybeScreen (created by CardStack) in RNSScreenContainer (created by ScreenContainer) in ScreenContainer (created by MaybeScreenContainer) in MaybeScreenContainer (created by CardStack) in RCTView (created by View) in View (created by Background) in Background (created by CardStack) in CardStack (created by HeaderShownContext) in RNCSafeAreaProvider (created by SafeAreaProvider) in SafeAreaProvider (created by SafeAreaInsetsContext) in SafeAreaProviderCompat (created by StackView) in RNGestureHandlerRootView (created by GestureHandlerRootView) in GestureHandlerRootView (created by StackView) in StackView (created by StackNavigator) in PreventRemoveProvider (created by NavigationContent) in NavigationContent in Unknown (created by StackNavigator) in StackNavigator (created by App) in EnsureSingleNavigator in BaseNavigationContainer in ThemeProvider in NavigationContainerInner (created by App) in RCTView (created by View) in View (created by SafeAreaWrap) in SafeAreaWrap (created by App) in Provider (created by App) in App (created by withDevTools(App)) in withDevTools(App) in RCTView (created by View) in View (created by AppContainer) in RCTView (created by View) in View (created by AppContainer) in AppContainer in main(RootComponent)
Reducer代码
export function complaintReducer(state = initalComplaintsFormState, action) { switch (action.type) { //...other cases case GET_COMPLAINT_LIST: return { ...state, complaintList: action.payload }; default: return state; } }
ComplaintsMenu组件代码
//...other imports import { useSelector, useDispatch } from "react-redux"; import { getComplaintList } from "../Redux/Actions"; export default function ComplaintsMenu() { const { ComplaintList } = useSelector((state) => state.complaintReducer); const dispatch = useDispatch; // 我认为问题出在这里,因为dispatch函数(钩子?)在useEffect钩子中被调用,但我不清楚具体原因,也不知道如何实现需求,我是跟着下方的YouTube教程做的 useEffect(() => { dispatch(getComplaintList()); }, []); return ( <FlatList data={ComplaintList} renderItem={({ item }) => ( <ComplaintCard key={item.complaint_id} title={item.issue} status={item.status} /> )} /> );
依赖版本
{ "name": "poll-app", "version": "1.0.0", "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web" }, "dependencies": { "@expo-google-fonts/inter": "^0.2.2", "@expo/webpack-config": "^0.17.2", "@react-navigation/native": "^6.1.3", "@react-navigation/stack": "^6.3.12", "expo": "~47.0.12", "expo-status-bar": "~1.4.2", "react": "18.1.0", "react-dom": "18.1.0", "react-native": "0.70.5", "react-native-safe-area-context": "4.4.1", "react-native-screens": "~3.18.0", "react-native-web": "~0.18.9", "react-redux": "^8.0.5", "redux": "^4.2.1", "redux-thunk": "^2.4.2" }, "devDependencies": { "@babel/core": "^7.12.9", "eslint-plugin-react-hooks": "^4.6.0" }, "private": true }
已尝试操作
- 重新安装
react-redux和redux,执行npm update - 检查React版本一致性,确认所有依赖使用相同React版本
问题根源与修复方案
- Hook调用错误:
useDispatch是React-Redux提供的Hook,必须以函数形式调用才能获取到dispatch方法,你的代码中遗漏了括号:
// 错误写法 const dispatch = useDispatch; // 正确写法 const dispatch = useDispatch();
- 字段名不匹配:Reducer中定义的字段是
complaintList(小写开头),但组件中使用ComplaintList(大写开头),会导致无法获取到状态数据,同步字段名即可:
// 正确的状态获取写法 const { complaintList } = useSelector((state) => state.complaintReducer); // FlatList对应修改 <FlatList data={complaintList} renderItem={({ item }) => ( <ComplaintCard key={item.complaint_id} title={item.issue} status={item.status} /> )} />
- 异步Action检查:如果
getComplaintList是请求后端API的异步Action,需确保它是符合Redux-Thunk规范的函数,示例如下:
export const getComplaintList = () => async (dispatch) => { try { // 替换为你的后端API地址 const response = await fetch('https://your-api-url/complaints'); const data = await response.json(); dispatch({ type: GET_COMPLAINT_LIST, payload: data }); } catch (error) { console.error('获取投诉列表失败:', error); } };
内容的提问来源于stack exchange,提问作者EffDuBois
相关产品推荐
相关产品推荐

