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

React Native使用reducer时报“Invalid hook call”渲染错误崩溃如何解决

问题修复方案

核心错误原因

  • DeviceCard.tsx中调用了useNavigation钩子但未导入,直接触发Invalid hook call报错
  • DeviceCard.tsx中所有展示文本未正确使用模板字符串反引号包裹,存在语法错误
  • 存在其他非直接报错的逻辑隐患,也建议同步修复

修复步骤

1. 修复DeviceCard.tsx

完整修正后的代码如下:

import { useEffect, useState } from "react";
import { StyleSheet, Text, TouchableOpacity } from "react-native";
import { Device } from "react-native-ble-plx";
import { StackNavigationProp } from '@react-navigation/stack';
// 新增导入useNavigation
import { useNavigation } from '@react-navigation/native';

type DeviceCardProps = {
    device: Device;
};

const DeviceCard = ({ device }: DeviceCardProps) => {
    console.log("I am here!");
    const navigation = useNavigation<StackNavigationProp<any>>();

    const [isConnected, setIsConnected] = useState(false);

    useEffect(() => {
        // 修正isConnected返回值的处理逻辑
        device.isConnected().then((connected) => setIsConnected(connected));
    }, [device]);

    return (
      <TouchableOpacity
        style={styles.container}
        onPress={() => navigation.navigate('Device', { device })}>
        {/* 修正所有模板字符串的反引号包裹 */}
        <Text>{`Id : ${device.id}`}</Text>
        <Text>{`Name : ${device.name}`}</Text>
        <Text>{`Is connected : ${isConnected}`}</Text>
        <Text>{`RSSI : ${device.rssi}`}</Text>
        <Text>{`Manufacturer : ${device.manufacturerData?.replace(/[=]/g, '')}`}</Text>
        <Text>{`ServiceData : ${device.serviceData}`}</Text>
        <Text>{`UUIDS : ${device.serviceUUIDs}`}</Text>
      </TouchableOpacity>
    );
};

const styles = StyleSheet.create({
    container: {
      backgroundColor: 'white',
      marginBottom: 12,
      borderRadius: 16,
      shadowColor: 'rgba(60,64,67,0.3)',
      shadowOpacity: 0.4,
      shadowRadius: 10,
      elevation: 4,
      padding: 12,
    },
});

export { DeviceCard };

2. 补充校验Navigation容器

确认你的App组件外层已经被@react-navigation/native的NavigationContainer组件包裹,useNavigation只能在Navigation容器的后代组件中调用,否则仍会触发hook调用错误。

3. (可选)优化App.tsx的头部组件

将ListHeaderComponent移到App组件外部,避免每次重渲染生成新的组件实例导致不必要的性能损耗:

// 移到App组件外部
const ListHeaderComponent = ({isLoading, dispatch, scanDevices}: {isLoading: boolean, dispatch: any, scanDevices: () => void}) => (
  <View style={styles.body}>
    <View style={styles.sectionContainer}>
      <Text style={styles.sectionTitle}>Devices</Text>
    </View>
    <View style={styles.sectionContainer}>
      <Button
        title="Clear devices"
        onPress={() => dispatch({ type: 'CLEAR' })}
      />
      {isLoading ? (
        <View style={styles.activityIndicatorContainer}>
          <ActivityIndicator color={'teal'} size={25} />
        </View>
      ) : (
        <Button title="Scan devices" onPress={scanDevices} />
      )}
    </View>
  </View>
);

// App组件内调用时传入props即可
const App = () => {
  // ...原有逻辑
  return (
    <SafeAreaView style={styles.body}>
      <FlatList
        keyExtractor={(item) => item.id}
        data={scannedDevices}
        renderItem={({ item }) => <DeviceCard device={item} />}
        ListHeaderComponent={() => <ListHeaderComponent isLoading={isLoading} dispatch={dispatch} scanDevices={scanDevices} />}
        contentContainerStyle={styles.content}
      />
    </SafeAreaView>
  );
}

4. (可选)恢复权限检查逻辑

将注释掉的权限检查逻辑放在useEffect中调用,不要直接在组件顶层执行异步函数:

const App = () => {
  useEffect(() => {
    const checkPermission = async () => {
      let granted = await requestLocationPermission();
      while(!granted) {
        granted = await requestLocationPermission();
      }
    }
    checkPermission();
  }, [])
  // ...原有逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 12:06:02