Nextjs 中未定义 RTCPeerConnection
2023-03-02
371
我想使用 React 上下文 API 将 RTCPeerConnection 实例传递给我的 React 组件树。我知道 Nextjs SSR 功能,它首先在服务器端渲染组件。我看到许多针对此问题的解决方案,我可以使用 next/dynamic imports 来动态导入 React 组件或使用 useEffect 中的 Awaited import 加载 SDK,但它们都不符合我的需求。这是代码;请分享您能想到的最佳架构。
//RTCProvider.tsx
import { createContext, useCallback, useReducer } from "react";
import React from "react";
const configuration = {
iceServers: [
{
urls: "stun:stun.l.google.com:13902",
},
],
};
class MyRTCConnection extends RTCPeerConnection {
public chatChannel: RTCDataChannel;
public remoteClient: string | object;
constructor(config: RTCConfiguration) {
super(config);
this.chatChannel = this.createDataChannel("chat");
this.ondatachannel = (event) => {
const dataChannel = event.channel;
dataChannel.onopen = () => {
console.log(
"peer connection is ready to receive data channel messages"
);
};
};
this.onconnectionstatechange = (event) => {
console.log(event);
if (this.connectionState === "connected") {
console.log("succesfully connected with other peer");
}
};
}
async generateOffer(
offerOption: RTCOfferOptions
): Promise<RTCSessionDescriptionInit> {
// if (!this.getSenders()) {
// throw Error("No senders yet");
// }
const offer = await this.createOffer(offerOption);
this.setLocalDescription(offer);
return offer;
}
async acceptAnswer(answer:any){
this.setRemoteDescription(answer)
}
async acceptOfferAndCreateAnswer(
remoteOffer: any | RTCSessionDescriptionInit
): Promise<RTCSessionDescriptionInit> {
// if (!this.getSenders()) {
// throw Error("No senders yet");
// }
this.setRemoteDescription(remoteOffer);
const answer = await this.createAnswer();
this.setLocalDescription(answer);
return answer;
}
setRemoteClient(data: any): void {
this.remoteClient = data;
}
}
const rtcConn = new MyRTCConnection(configuration);
const RTCContext = createContext<MyRTCConnection | null>(rtcConn);
function RTCProvider({ children }: any) {
return (
<RTCContext.Provider value={rtcConn}>
{/* <RTCActionContext.Provider value={rtcActions}> */}
{children}
{/* </RTCActionContext.Provider> */}
</RTCContext.Provider>
);
}
export default RTCProvider;
export { RTCContext };
我的 _app.tsx
// src/pages/_app.tsx
import "@/styles/global.css";
import "@/styles/home.css";
import { ReactNode,useContext } from "react";
import type { AppProps, AppLayoutProps } from "next/app";
import { store } from "app/store";
import { Provider } from "react-redux";
import MediaProvider from "@/app/context/MediaProvider";
import IncomingCallModal from "@/components/modals/IncomingCallModal";
import SocketProvider, { SocketContext } from "@/app/context/SocketProvider";
import RTCProvider, { RTCContext } from "@/app/context/RTCProvider";
export default function App({ Component, pageProps }: AppLayoutProps) {
const getLayout = Component.getLayout || ((page: ReactNode) => page);
return (
<Provider store={store}>
<SocketProvider>
<MediaProvider>
<RTCProvider>
<IncomingCallModal />
{getLayout(<Component {...pageProps} />)}
</RTCProvider>
</MediaProvider>
</SocketProvider>
</Provider>
);
}
在
_app.txs
中导入 Provider 时,它会引发如下错误:-
12 |
13 |
> 14 | class MyRTCConnection extends RTCPeerConnection {
| ^
15 | public chatChannel: RTCDataChannel;
16 | public remoteClient: string | object;
17 |
ReferenceError: RTCPeerConnection is not defined
因此,我尝试了这个等待的导入,以在客户端动态导入 RTCProvider;
// src/pages/_app.tsx
// import RTCProvider, { RTCContext } from "@/app/context/RTCProvider";
var RTCProvider
(async () => {
RTCProvider = (await import("@/app/context/RTCProvider")).default;
})();
console.log(RTCProvider); // undefined
但浏览器控制台中的 RTCProvider 未定义。使这种方法奏效将是我的最后一步,我正在寻找不同的方法来解决这个问题。
2个回答
console.log 中出现未定义的原因是由于 Promise。控制台在 RTCProvider 承诺解析之前打印。
虽然不确定您使用的是哪个 nextJS 版本,但您可以尝试使用 next/dynamic。不确定 import await 方法。
import dynamic from "next/dynamic"
const RTCProvider = dynamic(() => import("@/app/context/RTCProvider"), {
ssr: false,
})
然后从您的 RTCProvider 进行打印。
function RTCProvider({ children }: any) {
console.log('x')
...
}
Han
2023-04-27
这就是我所发现的。
import { createContext, useCallback, useReducer } from "react";
import React from "react";
import { store } from "@/app/store";
import { addChatMessage } from "../store/chatSlice";
import handleChat from "../store/actionThunks/handleChat";
const configuration = {
iceServers: [
{
urls: "stun:stun.l.google.com:13902",
},
],
};
if (typeof window != "undefined") {
class MyRTCConnection extends RTCPeerConnection {
public chatChannel: RTCDataChannel;
public metaChannel: RTCDataChannel;
public remoteClient: string | object;
constructor(config: RTCConfiguration) {
super(config);
this.chatChannel = this.createDataChannel("chat");
this.ondatachannel = (eve) => {
const dataChannel = eve.channel;
// Switching by data channel name due
switch (dataChannel.label) {
case "chat":
dataChannel.onmessage = (event) => {
const message = JSON.parse(event.data);
store.dispatch(handleChat(message));
};
}
};
this.onconnectionstatechange = (event) => {
if (this.connectionState === "connected") {
console.log("succesfully connected with other peer");
}
};
}
async generateOffer(
offerOption: RTCOfferOptions
): Promise<RTCSessionDescriptionInit> {
// if (!this.getSenders()) {
// throw Error("No senders yet");
// }
const offer = await this.createOffer(offerOption);
this.setLocalDescription(offer);
return offer;
}
async acceptAnswer(answer: any) {
this.setRemoteDescription(answer);
}
async acceptOfferAndCreateAnswer(
remoteOffer: any | RTCSessionDescriptionInit
): Promise<RTCSessionDescriptionInit> {
// if (!this.getSenders()) {
// throw Error("No senders yet");
// }
this.setRemoteDescription(remoteOffer);
const answer = await this.createAnswer();
this.setLocalDescription(answer);
return answer;
}
setRemoteClient(data: any): void {
this.remoteClient = data;
}
}
var rtcConn = new MyRTCConnection(configuration) as MyRTCConnection;
var RTCContext = createContext<MyRTCConnection | null>(rtcConn);
} else {
var RTCContext = createContext(rtcConn);
}
function RTCProvider({ children }: any) {
return <RTCContext.Provider value={rtcConn}>{children}</RTCContext.Provider>;
}
export default RTCProvider;
export { RTCContext };
该应用程序也运行良好。
KAVYA SHARMA
2023-05-22