React+Node.js流媒体项目遇Navigator is not defined报错求助
错误根源在于你把Peer实例的初始化放在了组件顶层代码中,如果项目采用服务端渲染(比如Next.js),服务器环境没有浏览器专属的navigator、window等API,顶层代码会在服务器端执行,直接触发报错。你虽然在useEffect里加了浏览器环境判断,但Peer实例的创建不在这个判断范围内,所以问题没解决。
修复方案
- 将Peer实例的初始化移到
useEffect内部,确保只在浏览器环境执行 - 所有依赖浏览器API的操作(比如
getUserMedia、DOM操作)都包裹在浏览器环境判断中 - 添加组件卸载时的清理逻辑,避免内存泄漏
修改后的完整代码
import { useEffect, useRef } from 'react'; import Peer from 'peerjs'; const StreamComponent = () => { const streamBlock = useRef(null); const myPeer = useRef(null); // 用useRef存储Peer实例 useEffect(() => { // 只在浏览器环境执行 if (typeof window === 'undefined') return; // 初始化Peer实例 myPeer.current = new Peer(undefined, { host: "/", port: "3002", }); const room = window.location.pathname.split('/')[1]; const myVid = document.createElement('video'); myVid.muted = true; myPeer.current.on('open', id => { socket.emit('join-room', room, id); console.log(room); }); navigator.mediaDevices.getUserMedia({ video: true, audio: true, }).then(stream => { addStream(myVid, stream); myPeer.current.on('call', call => { call.answer(stream); const video = document.createElement('video'); call.on('stream', userStream => { addStream(video, userStream); }); }); }); // 组件卸载时清理Peer连接 return () => { if (myPeer.current) { myPeer.current.destroy(); } }; }, []); const addStream = (video, stream) => { if (!streamBlock.current) return; video.srcObject = stream; video.addEventListener('loadedmetadata', () => { video.play(); }); streamBlock.current.append(video); }; return <div ref={streamBlock}></div>; }; export default StreamComponent;
额外说明
- 用
useRef存储Peer实例,避免组件重渲染时重复创建 - 卸载时调用
destroy()关闭Peer连接,防止残留连接占用资源 - 增加了
streamBlock.current的空判断,避免DOM未挂载时的报错
内容的提问来源于stack exchange,提问作者Tyler Chen
相关产品推荐
相关产品推荐

