You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native自定义useGeolocation Hook调用报Invalid hook call错误求助

React Native自定义Hook调用报错:Invalid hook call问题排查与修复

我在React Native应用中尝试使用自定义Hook useGeolocation 获取用户坐标,但在handleUpdateLocation方法中调用该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

我的组件都是函数式组件,以下是组件代码和简化后的Hook代码,想请教问题出在哪里?

组件代码

//import * as React from 'react';
import { View, Text, StyleSheet,TouchableOpacity, Platform,PermissionsAndroid, BackHandler, ScrollView, TextInput, ActivityIndicator ,SafeAreaView} from 'react-native';
import React, { useState, useEffect } from 'react'
import { observer } from 'mobx-react'
import  useGeolocation  from '@hooks/useGeolocation.js';

export default OrderCard14 = observer((props) => 
{
    const handleUpdateLocation = async (gender) =>
    {
        const { coordinates, city } = useGeolocation(true);
    };

    return(
        <View style={{ flex:1,backgroundColor:'white',alignItems:'center',padding:0 }}>
            
        </View>
    );
});

自定义Hook代码

//import AsyncStorage from '@react-native-async-storage/async-storage';
import { AsyncStorage ,Platform, Alert, PermissionsAndroid } from 'react-native';
import _ from 'lodash';
import env from '@env/vars';
import http from '@env/axiosin';
import Geolocation from 'react-native-geolocation-service';
import { useStore } from '@hooks/use-store';

const useGeolocation = (getCityName = false) => {
    const root = useStore();
    const [coordinates, setCoordinates] = useState(false);
    const [city, setCity] = useState(false);

    const requestLocationPermissions = async () =>
    {
        console.log('getting new coordinates');
        if (Platform.OS === 'ios')
        {
            const auth = await Geolocation.requestAuthorization("whenInUse");
            if(auth === "granted")
            {
                //root.mapStore.setLocationEnabled(true);
                this.locationEnabled = true;
                let coords = await getMe(getCityName);
                return coords;
                /*
                const todayId = moment().isoWeekday();
                if(todayId != root.userStore.user.lastLoginDayId)
                {
                    getMe();
                }
                */
            }
            else
            {
                //Alert.alert('PLEASE ENABLE LOCATION');
                root.mapStore.setLocationEnabled(false);
                //this.locationEnabled = false;
            }
        }
        if (Platform.OS === 'android')
        {
            let granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
            if (granted === PermissionsAndroid.RESULTS.GRANTED) 
            {
            // do something if granted...
            
                //this.loactionEnabled = true;
                root.mapStore.setLocationEnabled(true);
                let coords = await getMe();
                return coords;
                /*
                const todayId = moment().isoWeekday();
                if(todayId != root.userStore.user.lastLoginDayId)
                {
                    getMe();
                }
                */
            }
            else
            {
                //Alert.alert('KULO');
                root.mapStore.setLocationEnabled(false);
                //this.locationEnabled = false;
            }
        }
    }

    useEffect(() => {
        requestLocationPermissions();
    }, []);
    console.log('returning new coordinates with hook: '+coordinates);
    return { coordinates, city };
};

export default useGeolocation;

问题根源

你直接违反了React Hooks的核心规则:Hooks只能在函数组件的顶层作用域调用,绝对不能在嵌套函数(比如handleUpdateLocation)、条件语句或循环中调用。在事件处理函数内部调用useGeolocation,是触发该错误的直接原因。

另外你的useGeolocation还有两处明显问题:

  1. Hook是函数式逻辑,不存在this,代码中this.locationEnabled属于错误用法;
  2. getMe函数未定义,需要补充实现或修正调用逻辑。

修复方案

第一步:改造自定义Hook

给Hook添加手动触发更新的方法,将位置获取逻辑封装成可调用的函数,同时修正this的错误用法:

//import AsyncStorage from '@react-native-async-storage/async-storage';
import { Platform, Alert, PermissionsAndroid } from 'react-native';
import _ from 'lodash';
import env from '@env/vars';
import http from '@env/axiosin';
import Geolocation from 'react-native-geolocation-service';
import { useStore } from '@hooks/use-store';
import { useState, useEffect } from 'react';

const useGeolocation = (getCityName = false) => {
    const root = useStore();
    const [coordinates, setCoordinates] = useState(false);
    const [city, setCity] = useState(false);

    // 封装位置获取核心逻辑,暴露给外部调用
    const getLocation = async () => {
        console.log('getting new coordinates');
        if (Platform.OS === 'ios') {
            const auth = await Geolocation.requestAuthorization("whenInUse");
            if (auth === "granted") {
                root.mapStore.setLocationEnabled(true);
                // 补充实现getMe函数,传入getCityName参数
                const coords = await getMe(getCityName);
                setCoordinates(coords);
                // 如果getMe返回城市信息,同步更新city状态
                // setCity(...)
            } else {
                root.mapStore.setLocationEnabled(false);
            }
        }
        if (Platform.OS === 'android') {
            let granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
            if (granted === PermissionsAndroid.RESULTS.GRANTED) {
                root.mapStore.setLocationEnabled(true);
                const coords = await getMe(getCityName);
                setCoordinates(coords);
            } else {
                root.mapStore.setLocationEnabled(false);
            }
        }
    };

    // 组件挂载时自动获取一次位置
    useEffect(() => {
        getLocation();
    }, []);

    console.log('returning new coordinates with hook: ', coordinates);
    // 返回状态和手动更新方法
    return { coordinates, city, getLocation };
};

export default useGeolocation;

第二步:修正组件代码

将Hook移到组件顶层作用域,在事件处理函数中调用Hook返回的getLocation方法:

//import * as React from 'react';
import { View, Text, StyleSheet,TouchableOpacity, Platform,PermissionsAndroid, BackHandler, ScrollView, TextInput, ActivityIndicator ,SafeAreaView} from 'react-native';
import React from 'react'
import { observer } from 'mobx-react'
import useGeolocation from '@hooks/useGeolocation.js';

export default OrderCard14 = observer((props) => 
{
    // 顶层调用Hook,符合Hooks规则
    const { coordinates, city, getLocation } = useGeolocation(true);

    const handleUpdateLocation = async () => {
        // 调用Hook提供的方法手动更新位置
        await getLocation();
        // 更新后可直接使用coordinates和city状态
        console.log('更新后的坐标:', coordinates);
    };

    return(
        <View style={{ flex:1,backgroundColor:'white',alignItems:'center',padding:0 }}>
            {/* 添加触发更新的按钮 */}
            <TouchableOpacity onPress={handleUpdateLocation} style={{ padding:10, backgroundColor:'#1677ff', marginTop:20 }}>
                <Text style={{ color:'white' }}>更新位置</Text>
            </TouchableOpacity>
        </View>
    );
});

额外注意事项

  • 确保React和React Native版本匹配,避免版本不一致引发的Hook问题;
  • 用npm ls react或yarn list react命令排查项目中是否存在多个React副本;
  • 补充实现getMe函数,确保它能正确获取坐标和城市信息并返回。

内容的提问来源于stack exchange,提问作者gabogabans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:55:23