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
相关产品推荐
相关产品推荐

