开发者问题收集

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