【问题标题】:How can I create a separate dynamic window in my React app?如何在我的 React 应用程序中创建一个单独的动态窗口?
【发布时间】:2021-01-29 13:20:58
【问题描述】:

我的 React 应用包含视频聊天功能(通过 Twilio)。用户转到仪表板,然后单击按钮开始呼叫。这会提示 VideoCall 组件被实例化和显示。在实例化时,它连接到后端 Twilio 服务以获取访问令牌,然后连接到 Twilio 以创建调用、设置事件处理程序等。

目前我在仪表板的 div 中显示视频窗口,但我希望它们显示在弹出窗口中。我尝试过使用 react-new-window,也尝试过 React Portals,但我对我在做什么以使其正常工作知之甚少。

目前我有以下Dashboard 组件:

function Dashboard(props) {

  const { displayInfo} = props
  const [ callInitiated, setCallInitiated ] = useState(false)

  const initCall = () => {
    setCallInitiated(true)
  }

  return (
    <div id="dashboard">
      {callInitiated ? <VideoCall displayInfo={displayInfo} /> : null }
      <div> ...rest of dashboard, including button which calls 'initCall' on being clicked... </div>
    </div>
  )

}

export default Dashboard

我的VideoCall 组件是:

const Video = require('twilio-video');

// Get access token from backend service
async function getAccessToken(identity) {

    const url = `${process.env.REACT_APP_TWILIO_TOKEN_SERVICE}?identity=${identity}`;
    try {
        const response = await axios.get(`${url}`, AXIOS_HEADERS);
        return response.data.accessToken;
    } catch {
        return null;
    }

}

// VideoCall component
function VideoCall(props) {

    const { displayInfo} = props

    // Connect to Twilio server function to get access token
    getAccessToken('Tester')
    .then((token) => {
      Video.connect(token, {
        name: 'Test room'
      })
      .then(room => {
        participantConnected(room.localParticipant);
        room.participants.forEach(participantConnected);
        room.on('participantConnected', participantConnected);
        room.on('participantDisconnected', participantDisconnected);
        room.once('disconnected', error => room.participants.forEach(participantDisconnected))
      })
    });

    function participantConnected(participant) {
    
      const div = document.createElement('div');
      div.id = participant.sid;
    
      participant.on('trackSubscribed', track => trackSubscribed(div, track));
      participant.on('trackUnsubscribed', trackUnsubscribed);
    
      participant.tracks.forEach(publication => {
          trackSubscribed(div, publication.track);
      });

      if(participant.identity === 'Tester') {
        document.getElementById('myVideoWindow').appendChild(div)
      }
      
    }
    
    function participantDisconnected(participant) {
      document.getElementById(participant.sid).remove();
    }
    
    function trackSubscribed(div, track) {
      div.appendChild(track.attach());
    }
    
    function trackUnsubscribed(track) {
      track.detach().forEach(element => element.remove());
    }

    return (
          <div id="callWrapper" className="callOuterWrapper">
              <div className="titleBar">
                  <h1 className="pageHeader">Calling {displayInfo.receiverName}</h1>
              </div>
              <div className="videoRoom">
                    <div id="myVideoWindow" className="callWindow"></div>
                    <div className="callInfo"> ...this will contain info on call status... </div>
                    <div id="receiverWindow" className="callWindow"></div>
              </div>
          </div>
    )
}

export default VideoCall

到目前为止,这是可行的。用户单击按钮,视频窗口按预期出现在仪表板的顶部。

现在我想将VideoCall 组件拉到一个单独的窗口中(这样用户在通话时仍然可以看到仪表板。

我尝试了 react-new-window 包,它只是将VideoCall 包装在NewWindow 中。我尝试将它包装在 Dashboard 组件中:

<div id="dashboard">
  {callInitiated ? <NewWindow><VideoCall displayInfo={displayInfo} /></NewWindow> : null }
  <div> ...rest of dashboard, including button which calls 'initCall' on being clicked... </div>
</div>

当这不起作用时,我尝试在 VideoCall 组件中进行包装:

<NewWindow>
   <div id="callWrapper" className="callOuterWrapper">...</div>
</NewWindow>

在这两种情况下,这都会显示带有空 callWrapper div 的新窗口;但是,一旦到达document.getElementById('myVideoWindow').appendChild(div),它就无法找到该 div。被引用的 DOM 似乎是来自仪表板窗口而不是新窗口的 DOM(此外,任何 console.log 命令都会记录到原始窗口的控制台,而不是新窗口)。

然后我尝试拆开 NewWindow 代码并创建自己的定制版本,但我对它如何工作以使其满足我的需要并不了解。

那么,有没有办法从其中的组件访问新窗口的 DOM?还是我应该采取不同的方法?

【问题讨论】:

    标签: reactjs twilio react-portal


    【解决方案1】:

    这里是 Twilio 开发者宣传员。

    使用原生 DOM 方法直接访问 DOM,例如 document.getElementById,在 React 中有点不受欢迎。 React 本身应该负责在 DOM 中添加和删除内容。

    我在how to build a video chat with React 上写了一篇文章,介绍了如何在不直接访问 DOM 的情况下将参与者添加到页面。

    我建议您查看一下,也许更新您的应用,这样您就不必使用document.getElementById,然后希望&lt;NewWindow&gt; 组件应该像宣传的那样工作。

    【讨论】:

    • 谢谢;我明天试试!
    • 告诉我进展如何!
    • 我最终改变了它的工作方式,以便视频与其他视频在同一个窗口中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2020-06-05
    相关资源
    最近更新 更多