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

React Native Zeroconf报错:Cannot read property 'scan' of null求助

问题分析与解决方案

核心错误原因

cannot read property 'scan' of null 本质是**react-native-zeroconf 不兼容 Expo Managed Workflow**:该库需要原生代码链接,但Expo Managed环境无法直接使用这类依赖原生模块的库,导致new Zeroconf()返回null,进而调用scan时触发错误。

同时你的代码存在逻辑问题:

  • 在组件顶层直接调用zeroconf.scan和监听found事件,会导致组件每次渲染时重复执行这些操作
  • useEffect钩子被嵌套在zeroconf.on("found")回调中,违反了React钩子必须在组件顶层调用的规则

修复步骤

1. 替换为Expo兼容的mDNS库

卸载react-native-zeroconf,安装Expo官方提供的expo-mdns:

npm uninstall react-native-zeroconf
npx expo install expo-mdns

2. 重构HomeScreen代码

修正生命周期逻辑,使用expo-mdns进行服务发现,同时规范React钩子的使用:

import React, { useState, useEffect, useRef } from "react";
import { View } from "react-native";
import init from "react_native_mqtt";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { useMdnsDiscovery } from "expo-mdns";

import TemperatureGauge from "../components/TemperatureGauge";
import AlertIndicator from "../components/AlertIndicator";

// 初始化MQTT
init({
  size: 10000,
  storageBackend: AsyncStorage,
  defaultExpires: 1000 * 3600 * 24,
  enableCache: true,
  reconnect: true,
  sync: {},
});

function HomeScreen() {
  const [temperature, setTemperature] = useState(0);
  const [alert, setAlert] = useState("");
  // 使用useRef保存MQTT客户端实例,避免重复创建
  const clientRef = useRef(null);

  // 使用expo-mdns扫描指定服务
  const { services, isDiscovering } = useMdnsDiscovery({
    serviceType: "_tcp",
    protocol: "local",
    name: "mqttbroker",
  });

  // 处理发现的MQTT服务
  useEffect(() => {
    // 如果已有客户端连接,先断开
    if (clientRef.current?.isConnected()) {
      clientRef.current.disconnect();
      clientRef.current = null;
    }

    // 取第一个发现的服务
    const mqttService = services[0];
    if (!mqttService) return;

    const { addresses, port } = mqttService;
    const clientId = `id_${parseInt(Math.random() * 100000)}`;

    // 创建MQTT客户端
    const client = new Paho.Client(
      addresses[0],
      port,
      "/mqtt",
      clientId
    );

    // 连接成功回调
    function onConnect() {
      console.log("Connected to MQTT broker");
      client.subscribe("temperature", { qos: 0 });
      client.subscribe("alert", { qos: 0 });
    }

    // 连接丢失回调
    function onConnectionLost(responseObject) {
      if (responseObject.errorCode !== 0) {
        console.log(`Connection lost: ${responseObject.errorMessage}`);
      }
    }

    // 消息到达回调
    function onMessageArrived(message) {
      console.log(`Message arrived: ${message.payloadString}`);
      if (message.destinationName === "temperature") {
        setTemperature(parseFloat(message.payloadString));
      } else if (message.destinationName === "alert") {
        setAlert(message.payloadString);
      }
    }

    // 绑定回调
    client.onConnectionLost = onConnectionLost;
    client.onMessageArrived = onMessageArrived;

    // 连接MQTT服务器
    client.connect({ onSuccess: onConnect, useSSL: false, timeout: 3 });

    // 保存客户端实例到ref
    clientRef.current = client;

    // 组件卸载时断开连接
    return () => {
      if (clientRef.current?.isConnected()) {
        clientRef.current.disconnect();
      }
    };
  }, [services]); // 当发现的服务列表变化时重新执行

  return (
    <View>
      <TemperatureGauge temperature={temperature} />
      <AlertIndicator alert={alert} />
    </View>
  );
}

export default HomeScreen;

3. 额外注意事项

  • 确保ESP8266设备和Android模拟器处于同一局域网,模拟器默认使用桥接网络,可通过局域网IP直接测试连接
  • Expo Android模拟器会自动处理expo-mdns所需的网络权限,无需额外配置
  • 若服务发现不稳定,可尝试重启ESP8266的mDNS服务,或手动指定IP地址验证MQTT连接是否正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:25:15