React中Invalid hook call错误:配置文件误用useState Hook的排查
解决React Hook调用错误:Invalid hook call
错误原因
你触发的Error: Invalid hook call. Hooks can only be called inside of the body of a function component错误,核心是违反了React Hooks的使用规则:Hooks只能在函数组件的顶层或者自定义Hook内部调用,不能在普通模块的全局作用域直接使用。你在配置文件的顶层作用域声明useState,完全不符合规范。
同时原代码存在另一个问题:导出的userCurrentWindow、userDrivingStatus等依赖状态的变量是一次性赋值的,即使后续调用setState更新状态,这些导出变量也不会同步更新,无法实现状态共享的需求。
解决方案:用自定义Hook封装状态与操作
将状态逻辑封装成自定义Hook,既符合Hooks规则,又能让组件获取实时更新的状态值。
1. 修改配置文件(重命名为useUserAuth.js)
import React, { useState, useMemo } from 'react' export const useUserAuth = () => { // 在自定义Hook内部声明状态,符合规则 const [state, setState] = useState({ drivingStatus: false, currentWindow: 'driver' }); // 用函数式更新确保获取最新状态 const drivingRequest = () => { setState(prevState => ({ ...prevState, drivingStatus: !prevState.drivingStatus })); } const switchWindow = () => { setState(prevState => ({ ...prevState, currentWindow: prevState.currentWindow === 'driver' ? 'user' : 'driver' })); } // 静态用户信息(无需更新的常量) const staticUserInfo = { userFirstName: 'xxxx', userLastName: 'xxxx', userCountry: '', userCountryStatus: 'active', userRegion: '', userIso: '', userIso3: '', userLocale: 'en-US', userLanguage: '', userWalletBalance: 0, userNotification: 0, userAccountType: 'driver', userDriverID: '' }; // 依赖状态的计算值,用useMemo缓存避免重复计算 const computedValues = useMemo(() => ({ userCurrentWindow: state.currentWindow, userDrivingStatus: state.drivingStatus, userAverageRating: staticUserInfo.userAccountType === 'driver' && state.currentWindow === 'driver' ? 3.9 : 2.8 }), [state, staticUserInfo.userAccountType]); // 合并所有需要导出的内容 return { ...staticUserInfo, ...computedValues, drivingRequest, switchWindow }; }
2. 修改引用组件(CustomDrawer.js)
import React from "react"; import { View, Text, Pressable, TouchableOpacity } from "react-native"; import { DrawerContentScrollView, DrawerItemList } from '@react-navigation/drawer'; import { useNavigation } from '@react-navigation/native'; import { useUserAuth } from './useUserAuth'; // 导入自定义Hook import Icon from 'react-native-vector-icons/MaterialIcons'; import AntDesign from 'react-native-vector-icons/AntDesign'; const CustomDrawer = (props) => { const navigation = useNavigation(); // 在组件内部调用自定义Hook,获取实时状态和方法 const { userFirstName, userLastName, userAverageRating, userWalletBalance, userIso3, userNotification, userCurrentWindow, userAccountType, userDriverID, userDrivingStatus, drivingRequest, switchWindow } = useUserAuth(); return ( <View> <Text>User first name: {userFirstName}</Text> {/* 示例:添加触发状态更新的按钮 */} <Pressable onPress={drivingRequest} style={{marginTop: 10}}> <Text>{userDrivingStatus ? '停止接单' : '开始接单'}</Text> </Pressable> <Pressable onPress={switchWindow} style={{marginTop: 10}}> <Text>切换窗口:{userCurrentWindow}</Text> </Pressable> {/* 其他组件内容 */} </View> ) } export default CustomDrawer;
关键说明
- 自定义Hook遵循Hooks规则,只能在函数组件或其他自定义Hook内部调用,彻底解决原错误。
- 使用函数式更新(
setState(prevState => ...))避免闭包陷阱,确保每次更新都基于最新的状态值。 - 用
useMemo缓存计算值,避免组件重渲染时重复执行计算逻辑,优化性能。 - 所有状态和方法通过自定义Hook统一管理,组件调用后能实时获取最新状态,解决了原代码中状态更新后导出变量不同步的问题。
内容的提问来源于stack exchange,提问作者Festus Akushie
相关产品推荐
相关产品推荐

