React.tsx应用如何从COM端口获取数据?求实现方案
解决方案
首先纠正一个误解:serialport完全支持TypeScript,不需要额外适配TSX——它本身就包含了完整的类型定义,直接安装就能在React.tsx项目中使用。不过要注意:浏览器环境无法直接访问COM端口,因为这属于Node.js的系统级API,所以你需要根据项目形态选择两种方案之一:
方案一:用Electron打包成桌面应用(推荐本地直接访问串口)
如果你的项目是面向桌面端的,Electron可以让React.tsx应用拥有Node.js的系统权限,直接调用serialport读取串口数据:
初始化Electron+React+TS项目
可以用现成模板快速搭建:npx create-react-app my-ship-app --template typescript cd my-ship-app npm install electron electron-builder --save-dev安装serialport
直接安装即可,TypeScript类型已内置:npm install serialport主进程处理串口逻辑
在Electron主进程(比如main.ts)中写串口读取代码,通过IPC通信把数据传给React渲染进程:import { app, BrowserWindow, ipcMain } from 'electron'; import { SerialPort } from 'serialport'; import { ReadlineParser } from '@serialport/parser-readline'; let mainWindow: BrowserWindow | null; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { contextIsolation: true, preload: `${__dirname}/preload.js` // 用preload做安全的IPC桥接 } }); mainWindow.loadURL('http://localhost:3000'); } app.whenReady().then(() => { createWindow(); // 初始化串口连接(替换为你的COM端口和波特率) const port = new SerialPort({ path: 'COM3', baudRate: 9600 }); const parser = port.pipe(new ReadlineParser({ delimiter: '\r\n' })); // 监听串口数据,发送给渲染进程 parser.on('data', (rawData) => { const parsedData = parseNMEAData(rawData); ipcMain.emit('ship-data', parsedData); }); }); // 示例:解析NMEA 0183格式的船舶数据 function parseNMEAData(raw: string) { const parts = raw.split(','); if (parts[0] === '$GPGGA') { return { latitude: parts[2], longitude: parts[4], altitude: parts[9] }; } return null; }React组件接收数据并计算
在preload脚本中暴露IPC接口,然后在React组件中监听数据:// preload.js const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electronAPI', { onShipData: (callback) => ipcRenderer.on('ship-data', callback) }); // React组件(ShipData.tsx) import { useEffect, useState } from 'react'; interface ShipData { latitude: string; longitude: string; altitude: string; } export default function ShipDataComponent() { const [data, setData] = useState<ShipData | null>(null); const [calculatedSpeed, setCalculatedSpeed] = useState<number>(0); useEffect(() => { const handleData = (_, parsedData: ShipData) => { setData(parsedData); // 添加船舶数据计算逻辑 const speed = calculateShipSpeed(parsedData); setCalculatedSpeed(speed); }; window.electronAPI.onShipData(handleData); return () => window.electronAPI.onShipData(handleData); }, []); // 示例计算逻辑 function calculateShipSpeed(data: ShipData): number { // 根据实际需求实现,比如基于经纬度变化计算航速 return 15.5; // 示例值 } return ( <div className="ship-data"> <h2>船舶实时数据</h2> {data ? ( <> <p>纬度: {data.latitude}</p> <p>经度: {data.longitude}</p> <p>计算航速: {calculatedSpeed} 节</p> </> ) : ( <p>等待串口数据...</p> )} </div> ); }
方案二:Node.js后端中转(适合Web端应用)
如果你的项目是Web端,无法直接访问本地串口,可以搭建一个Node.js后端,用serialport读取数据后通过API/WebSocket推送给React前端:
搭建Node.js后端
mkdir ship-data-server && cd ship-data-server npm init -y npm install serialport express ws后端代码示例(server.ts)
import express from 'express'; import WebSocket from 'ws'; import { SerialPort } from 'serialport'; import { ReadlineParser } from '@serialport/parser-readline'; const app = express(); const server = app.listen(3001, () => console.log('后端运行在3001端口')); const wss = new WebSocket.Server({ server }); const port = new SerialPort({ path: 'COM3', baudRate: 9600 }); const parser = port.pipe(new ReadlineParser({ delimiter: '\r\n' })); parser.on('data', (rawData) => { const parsedData = parseNMEAData(rawData); // 通过WebSocket推送给所有连接的前端 wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(parsedData)); } }); }); function parseNMEAData(raw: string) { const parts = raw.split(','); return parts[0] === '$GPGGA' ? { latitude: parts[2], longitude: parts[4] } : null; }React前端连接后端
// React组件 import { useEffect, useState } from 'react'; interface ShipData { latitude: string; longitude: string; } export default function ShipWebComponent() { const [data, setData] = useState<ShipData | null>(null); useEffect(() => { const ws = new WebSocket('ws://localhost:3001'); ws.onmessage = (event) => { const parsedData = JSON.parse(event.data); if (parsedData) { setData(parsedData); // 执行计算逻辑 const result = computeShipMetrics(parsedData); console.log(result); } }; return () => ws.close(); }, []); function computeShipMetrics(data: ShipData) { // 你的计算逻辑 return { distance: 100 }; } return ( <div> {data ? ( <> <p>纬度: {data.latitude}</p> <p>经度: {data.longitude}</p> </> ) : ( <p>连接后端中...</p> )} </div> ); }
关键注意事项
- 串口路径(如
COM3)和波特率必须与船舶设备的配置一致 - 船舶数据通常遵循NMEA 0183协议,需要根据具体报文格式编写解析逻辑
- 用Electron时,务必通过
preload脚本做IPC桥接,避免直接开启nodeIntegration带来的安全风险
内容的提问来源于stack exchange,提问作者Dylan Lucas
相关产品推荐
相关产品推荐

